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
Add AWS KMS support for OAuth2 Client Credentials JWT authentication #5942
Conversation
5c819ab
to
ab51d82
Compare
@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. |
ab51d82
to
8379036
Compare
✅ Deploy Preview for openpolicyagent ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
There was a problem hiding this 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.
docs/content/configuration.md
Outdated
| `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`. | |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
plugins/rest/auth.go
Outdated
Algorithm string `json:"algorithm"` | ||
} | ||
|
||
func converSignatureToBase64(alg string, der []byte) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: converSignatureToBase64
-> convertSignatureToBase64
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of the references are mentioned in the commit
References:
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I add this in the code
https://github.com/go-jose/go-jose/blob/v3/asymmetric.go#L501
92fba57
to
66ba0cb
Compare
I have tested this in our AWS environment (using |
docs/content/configuration.md
Outdated
| `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)`. | |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the changes.
docs/content/configuration.md
Outdated
| `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`. | |
There was a problem hiding this comment.
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 >}}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the changes.
You can share the OPA logs if any that exercise the workflow. |
1e8cf68
to
40ded4a
Compare
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. |
Attaching logs showing successful discovery, status & bundles calls using this mechanism |
40ded4a
to
6b24a2c
Compare
Now its "PR Check / Go Race Detector (pull_request)". Both failures look similar |
There was a problem hiding this 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.
docs/content/configuration.md
Outdated
| `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. | |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
6b24a2c
to
89c6ba9
Compare
89c6ba9
to
589dd6a
Compare
| `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 | |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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), | |||
}, | |||
{ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
3bcbd1f
to
f0d54a8
Compare
@@ -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) { |
There was a problem hiding this comment.
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
There was a problem hiding this 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>
f0d54a8
to
6dc46be
Compare
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:
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: