Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AWS KMS support for OAuth2 Client Credentials JWT authentication #5942

Conversation

prasanthu
Copy link
Contributor

@prasanthu prasanthu commented May 23, 2023

This implementaion adds new configuration properties to "oauth2" aws_kms: AWS KMS key details
aws_signing: Infomation for signing AWS requestion, similar to s3_signing

References:

  1. https://github.com/go-jose/go-jose/blob/v3/asymmetric.go#L501
  2. https://github.com/codelittinc/gobitauth/blob/master/sign.go#L101

Sample config file: https://gist.github.com/prasanthu/16e5e668ea864487d44dd7e95ff0d34b

Please refer to this Github issue for more details: #5892

Why the changes in this PR are needed?

What are the changes in this PR?

Notes to assist PR review:

Further comments:

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch 4 times, most recently from 5c819ab to ab51d82 Compare May 23, 2023 10:49
@ashutosh-narkar
Copy link
Member

@prasanthu thanks for working on this. Can you please add some tests and also instructions on how users can configure this. The later would need changes in this file.

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch from ab51d82 to 8379036 Compare May 24, 2023 14:25
@netlify
Copy link

netlify bot commented May 24, 2023

Deploy Preview for openpolicyagent ready!

Name Link
🔨 Latest commit 6dc46be
🔍 Latest deploy log https://app.netlify.com/sites/openpolicyagent/deploys/64a30a6346d80600084d7e13
😎 Deploy Preview https://deploy-preview-5942--openpolicyagent.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Member

@ashutosh-narkar ashutosh-narkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prasanthu thanks for the contribution. The changes look ok to me. Few comments in-line. Have you done some end-to-end tests with these changes? It would be interesting to know the results of some manual testing.

| `services[_].credentials.oauth2.aws_kms_key.algorithm` | `string` | Yes | Specifies the signing algorithm `(ECDSA_SHA_256, ECDSA_SHA_384 or ECDSA_SHA_512)`. |
| `services[_].credentials.oauth2.aws_signing.` | `{}` | No | AWS credentials for signing requests. Required if `aws_kms_key` is provided. |
| `services[_].credentials.oauth2.aws_signing.service` | `string` | Yes | The AWS service to sign requests with. Only `kms` is currently supported. |
| `services[_].credentials.oauth2.aws_signing.environment_credentials` | `{}` | Yes | See description for `services[_].credentials.s3_signing.environment_credential`. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the Static Environment Credentials method is supported here? What about other methods like Named Profile Credentials, EC2 Metadata Credentials etc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It supports all off them, I have updated the docs

Algorithm string `json:"algorithm"`
}

func converSignatureToBase64(alg string, der []byte) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: converSignatureToBase64 -> convertSignatureToBase64

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return nil, nil, fmt.Errorf("failed to unmarshall the signature from DER format %v", err)

}
// The format of our DER string is 0x02 + rlen + r + 0x02 + slen + s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this based on some standard? If yes, please include the references.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some references

}
// We serialize the outputs (r and s) into big-endian byte arrays and pad
// them with zeros on the left to make sure the sizes work out. Both arrays
// must be keyBytes long, and the output must be 2*keyBytes long.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above. If this is based on some standard please, include the references.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch 3 times, most recently from 92fba57 to 66ba0cb Compare June 2, 2023 11:46
@prasanthu
Copy link
Contributor Author

prasanthu commented Jun 2, 2023

@prasanthu thanks for the contribution. The changes look ok to me. Few comments in-line. Have you done some end-to-end tests with these changes? It would be interesting to know the results of some manual testing.

I have tested this in our AWS environment (using environment_credential). I am not sure how I can share the logs.

@ashutosh-narkar ashutosh-narkar marked this pull request as ready for review June 7, 2023 16:38
Comment on lines 384 to 386
| `services[_].credentials.oauth2.aws_kms_key` | `{}` | No | AWS KMS details for signing client assertions. Required only for signing with AWS KMS. |
| `services[_].credentials.oauth2.aws_kms_key.name` | `string` | Yes | To specify a KMS key, use its key ID, key ARN, alias name, or alias ARN. |
| `services[_].credentials.oauth2.aws_kms_key.algorithm` | `string` | Yes | Specifies the signing algorithm `(ECDSA_SHA_256, ECDSA_SHA_384 or ECDSA_SHA_512)`. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the aws_kms_key row. In the description for aws_kms_key.name and aws_kms_key.algorithm change the Required field to No. Also can you update the descriptions to explicitly mention that these fields are required only when using AWS KMS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the changes.

Comment on lines 387 to 392
| `services[_].credentials.oauth2.aws_signing.` | `{}` | No | AWS credentials for signing requests. Required if `aws_kms_key` is provided. Several methods of obtaining the necessary credentials are available; exactly one must be specified to use the AWS KMS signing. |
| `services[_].credentials.oauth2.aws_signing.service` | `string` | Yes | The AWS service to sign requests with. Only `kms` is currently supported. |
| `services[_].credentials.oauth2.aws_signing.environment_credentials` | `{}` | Yes | See description for `services[_].credentials.s3_signing.environment_credential`. |
| `services[_].credentials.oauth2.aws_signing.profile_credentials` | `{}` | No | See description for `services[_].credentials.s3_signing.profile_credentials`. |
| `services[_].credentials.oauth2.aws_signing.metadata_credentials` | `{}` | No | See description for `services[_].credentials.s3_signing.metadata_credentials`. |
| `services[_].credentials.oauth2.aws_signing.web_identity_credentials` | `{}` | No | See description for `services[_].credentials.s3_signing.web_identity_credentials`. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably replace this by adding a note in that section about how the credentials should be provided if AWS KMS signing is used. For ex,

{{< info >}}
ADD RELEVANT INFO
{{< /info >}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the changes.

@ashutosh-narkar
Copy link
Member

@prasanthu thanks for the contribution. The changes look ok to me. Few comments in-line. Have you done some end-to-end tests with these changes? It would be interesting to know the results of some manual testing.

I have tested this in our AWS environment (using environment_credential). I am not sure how I can share the logs.

You can share the OPA logs if any that exercise the workflow.

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch 4 times, most recently from 1e8cf68 to 40ded4a Compare June 15, 2023 14:02
@prasanthu
Copy link
Contributor Author

Not sure why "PR Check / Go compat build/test (ubuntu-22.04, 1.19) (pull_request)" is failing

@ashutosh-narkar
Copy link
Member

Not sure why "PR Check / Go compat build/test (ubuntu-22.04, 1.19) (pull_request)" is failing

We're seeing some test flakiness lately which we're looking into. Not related to the changes in this PR.

@prasanthu
Copy link
Contributor Author

@prasanthu thanks for the contribution. The changes look ok to me. Few comments in-line. Have you done some end-to-end tests with these changes? It would be interesting to know the results of some manual testing.

I have tested this in our AWS environment (using environment_credential). I am not sure how I can share the logs.

You can share the OPA logs if any that exercise the workflow.

Attaching logs showing successful discovery, status & bundles calls using this mechanism
sit.log

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch from 40ded4a to 6b24a2c Compare June 15, 2023 19:52
@prasanthu
Copy link
Contributor Author

Not sure why "PR Check / Go compat build/test (ubuntu-22.04, 1.19) (pull_request)" is failing

We're seeing some test flakiness lately which we're looking into. Not related to the changes in this PR.

Now its "PR Check / Go Race Detector (pull_request)". Both failures look similar

Copy link
Member

@ashutosh-narkar ashutosh-narkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prasanthu this is getting close. Thanks for addressing the comments. I had one more inline.

Comment on lines 384 to 385
| `services[_].credentials.oauth2.aws_kms_key.name` | `string` | No | To specify a KMS key, use its key ID, key ARN, alias name, or alias ARN. Required only for signing with AWS KMS. |
| `services[_].credentials.oauth2.aws_kms_key.algorithm` | `string` | No | Specifies the signing algorithm used by the key `aws_kms_key.name` `(ECDSA_SHA_256, ECDSA_SHA_384 or ECDSA_SHA_512)`. Required only for signing with AWS KMS. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about replacing aws_kms_key.name to aws_kms.key and aws_kms_key.algorithm to aws_kms.algorithm? Seems more future-proof if we need to add more fields for aws_kms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch from 89c6ba9 to 589dd6a Compare June 23, 2023 19:34
| `services[_].credentials.oauth2.token_url` | `string` | Yes | URL pointing to the token endpoint at the OAuth2 authorization server. |
| `services[_].credentials.oauth2.grant_type` | `string` | No | Defaults to `client_credentials`. |
| `services[_].credentials.oauth2.client_id` | `string` | No | The client ID to use for authentication. |
| `services[_].credentials.oauth2.signing_key` | `string` | No | Reference to private key used for signing the JWT. Required if `aws_kms` is not provided |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required if aws_kms is not provided this means if someone does not specify aws_kms, then this field has to be set? If that's the case then this would be backward incompatible. Or is this the current behavior already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a "Required" field before, with this feature you can either pass a private key or a KMS key.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Thanks for the clarification.

@@ -543,6 +543,55 @@ func TestNew(t *testing.T) {
}
}`, grantTypeClientCredentials),
},
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prasanthu we should have a test that exercises the workflow. There are examples of this in plugins/rest/rest_test.go. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a look at the TestOauth2ClientCredentialsJwtAuthentication. The current setup won't allow to mock the client_assertion creation.

Refer these methods:
https://github.com/open-policy-agent/opa/blob/main/plugins/rest/rest_test.go#L1632
https://github.com/open-policy-agent/opa/blob/main/plugins/rest/rest_test.go#L2002

Any pointers on how to mock the generation of client_assertion

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me understand where you would like to have the ability to mock the generation of client_assertion? We should be able to customize the test to accommodate this I would imagine.

Copy link
Contributor Author

@prasanthu prasanthu Jun 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we use KMS to sign the assertion, the SignDigest() gets invoked. It will send a signed AWS request to the KMS endpoint (based on the environment) for signing.
https://github.com/prasanthu/opa/blob/feature/kms-using-v4signed-request/internal/providers/aws/kms.go#L67
For mocking this part, we have to do something similar to the tests here: https://github.com/prasanthu/opa/blob/feature/kms-using-v4signed-request/internal/providers/aws/kms_test.go#L44

I am not sure how this can be done from a test like [TestOauth2ClientCredentialsJwtAuthentication](https://github.com/open-policy-agent/opa/blob/main/plugins/rest/rest_test.go#L1602)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Unless I'm missing something the test you mentioned creates a test server which SignDigest calls and then the test verifies the signature. We should be able to add a new similar test, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a test which implements your suggestion. Can you check TestOauth2ClientCredentialsGrantTypeWithKms

@prasanthu prasanthu force-pushed the feature/kms-using-v4signed-request branch 6 times, most recently from 3bcbd1f to f0d54a8 Compare July 1, 2023 07:26
@@ -2344,3 +2401,117 @@ func (m *myPluginMock) NewClient(c Config) (*http.Client, error) {
func (*myPluginMock) Prepare(*http.Request) error {
return nil
}

func TestOauth2ClientCredentialsGrantTypeWithKms(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test involving AWS KMS additions

Copy link
Member

@ashutosh-narkar ashutosh-narkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution @prasanthu!

This implementaion adds new configuration properties to "oauth2"
aws_kms: AWS KMS key details
aws_signing: Infomation for signing AWS requestion, similar to s3_signing

References:
1) https://github.com/go-jose/go-jose/blob/v3/asymmetric.go#L501
2) https://github.com/codelittinc/gobitauth/blob/master/sign.go#L101

Signed-off-by: Prasanth Ullattil <prasanth.ullattil@dnb.no>
@ashutosh-narkar ashutosh-narkar force-pushed the feature/kms-using-v4signed-request branch from f0d54a8 to 6dc46be Compare July 3, 2023 17:50
@ashutosh-narkar ashutosh-narkar merged commit db2f8ae into open-policy-agent:main Jul 3, 2023
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants