-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
KMS: Add list-key-rotations flag #12853
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
base: main
Are you sure you want to change the base?
Conversation
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.
Welcome to LocalStack! Thanks for raising your first Pull Request and landing in your contributions. Our team will reach out with any reviews or feedbacks that we have shortly. We recommend joining our Slack Community and share your PR on the #community channel to share your contributions with us. Please make sure you are following our contributing guidelines and our Code of Conduct.
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
6570477 to
fd7df95
Compare
| f"failed to satisfy constraint: Member must satisfy enum value set: [ALL_KEY_MATERIAL, ROTATIONS_ONLY]" | ||
| ) | ||
|
|
||
| if key.metadata["KeySpec"] != KeySpec.SYMMETRIC_DEFAULT: |
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.
As per AWS docs, for asymmetric keys when IncludeKeyMaterial is not provided we simply return the Rotations as empty [].
See here: https://docs.aws.amazon.com/kms/latest/developerguide/symm-asymm-compare.html#key-type-table
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.
question: From the test test_list_key_rotations_unsupported_key_types seems like it always raises an error for asymmetric keys, could you explain this a bit more here why it should be []?
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.
Based on the AWS Docs, and the behavior of the aws-cli, we return [] for unsupported KMS keys. But, whenever the attribute IncludeKeyMaterial is provided, it raises an error. See here: https://docs.aws.amazon.com/kms/latest/developerguide/key-state.html#key-state-table
In the test_list_key_rotations_unsupported_key_types we provide the IncludeKeyMaterial parameter.
| if include_key_material == IncludeKeyMaterial.ALL_KEY_MATERIAL: | ||
| rotation_history.append(rotation_entry) | ||
| else: # Default ROTATIONS_ONLY | ||
| if rotation.rotation_type in ["AUTOMATIC", "ON_DEMAND"]: |
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.
A KMS key on its creation doesn't have any rotation_type.
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 suggest its worth writing a test case to validate the behavior in case of automatically rotated keys, what do you think?
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 agree, it makes sense to add one. I'll do it. Thanks!
| initial_rotation = KeyRotationEntry( | ||
| key_id=self.metadata["Arn"], | ||
| key_material_state="CURRENT", | ||
| key_material_id=long_uid(), # FIXME: a more appropriate KMS output |
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.
Currently relying on uuid, open to suggestions.
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.
key_material_id should follow the constraints as mentioned in AWS documentation here: https://docs.aws.amazon.com/kms/latest/APIReference/API_RotationsListEntry.html#KMS-Type-RotationsListEntry-KeyMaterialId.
Hint: try playing around generating random bytes from os, you could find several references for it in the codebase 😉 and then try to convert it to a 64-character hexadecimal string.
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'm getting "Truncated": false here. Not entirely sure why it's being included, I do not see it on my awscli output; there is a discrepancy between AWS Docs and AWS CLI.
Removed them manually from this file (I know we're not supposed to manually edit it). Let me know if I should re-add it and make changes on the function's response payload.
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.
Rightly said 👍 I wouldn't manually make any changes in snapshot.
What i suggest here is to simple skip verification of Truncated in the test and add a TODO in there explaining the same discrepancy.
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 tackling this issue 🚀 The test coverage and your understanding of the issue looks decent 🙂 🎉
I have added a few comments and questions regarding the use of default classes, snapshots, testing, validations, rotation of automatic keys, etc.. Please feel free to reach out if anything is unclear, happy to clarify and help 🙂
| @dataclass | ||
| class KeyRotationEntry: | ||
| key_id: str | ||
| key_material: bytes | ||
| key_material_id: str | ||
| key_material_state: str | ||
| rotation_date: datetime.datetime | None = None | ||
| rotation_type: str | None = None | ||
| key_material_description: str | None = None | ||
| expiration_model: str | None = None | ||
| import_state: str | None = None | ||
| valid_to: str | None = None |
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.
Did you consider using the predefined class in __init__.py file which already includes this type RotationsListEntry?
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 don't know how I missed it. That is a valid point, I will refactor and use the classes from __init__.py
Thank you!
| if self.supports_rotation(): | ||
| initial_rotation = KeyRotationEntry( | ||
| key_id=self.metadata["Arn"], | ||
| key_material_state="CURRENT", |
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.
Instead of using hardcoded values, import the class defined in __init__.py file which already includes the types you have defined here.
The file is automatically generated, you can find more details here: https://github.com/localstack/localstack/blob/main/docs/localstack-concepts/README.md
| initial_rotation = KeyRotationEntry( | ||
| key_id=self.metadata["Arn"], | ||
| key_material_state="CURRENT", | ||
| key_material_id=long_uid(), # FIXME: a more appropriate KMS output |
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.
key_material_id should follow the constraints as mentioned in AWS documentation here: https://docs.aws.amazon.com/kms/latest/APIReference/API_RotationsListEntry.html#KMS-Type-RotationsListEntry-KeyMaterialId.
Hint: try playing around generating random bytes from os, you could find several references for it in the codebase 😉 and then try to convert it to a 64-character hexadecimal string.
| on_demand_count = sum( | ||
| 1 for rotation in self.key_rotations if rotation.rotation_type == "ON_DEMAND" | ||
| ) | ||
|
|
||
| if on_demand_count >= ON_DEMAND_ROTATION_LIMIT: |
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 happens if the rotation type is AUTOMATIC here?
| f"failed to satisfy constraint: Member must satisfy enum value set: [ALL_KEY_MATERIAL, ROTATIONS_ONLY]" | ||
| ) | ||
|
|
||
| if key.metadata["KeySpec"] != KeySpec.SYMMETRIC_DEFAULT: |
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.
question: From the test test_list_key_rotations_unsupported_key_types seems like it always raises an error for asymmetric keys, could you explain this a bit more here why it should be []?
| [ | ||
| ("RSA_2048", "SIGN_VERIFY", "ValidationException"), | ||
| ("RSA_4096", "ENCRYPT_DECRYPT", "ValidationException"), | ||
| ("ECC_NIST_P256", "SIGN_VERIFY", "ValidationException"), | ||
| ("HMAC_256", "GENERATE_VERIFY_MAC", "ValidationException"), |
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 add an id to these parameterised tests to make it more readable?
| key_id = kms_create_key(KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT")["KeyId"] | ||
|
|
||
| snapshot.add_transformer( | ||
| snapshot.transform.key_value("KeyMaterialId", reference_replacement=False) |
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.
Instead of adding it in every test, we should move the transformer to transformer_utility.py.
| with pytest.raises(ClientError) as e: | ||
| aws_client.kms.list_key_rotations(KeyId=key_id, IncludeKeyMaterial="INVALID_VALUE") |
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.
Since this usecase doesn't really belong to the intent of the test named test_list_key_rotations_include_key_material, we should write a separate test for this part.
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.
Rightly said 👍 I wouldn't manually make any changes in snapshot.
What i suggest here is to simple skip verification of Truncated in the test and add a TODO in there explaining the same discrepancy.
| "tests/aws/services/kms/test_kms.py::TestKMS::test_list_key_rotations_unsupported_key_types[RSA_2048-SIGN_VERIFY-UnsupportedOperationException]": { | ||
| "recorded-date": "16-07-2025, 15:59:30", | ||
| "recorded-content": {} | ||
| }, | ||
| "tests/aws/services/kms/test_kms.py::TestKMS::test_list_key_rotations_unsupported_key_types[RSA_4096-ENCRYPT_DECRYPT-UnsupportedOperationException]": { | ||
| "recorded-date": "16-07-2025, 15:59:31", | ||
| "recorded-content": {} | ||
| }, | ||
| "tests/aws/services/kms/test_kms.py::TestKMS::test_list_key_rotations_unsupported_key_types[ECC_NIST_P256-SIGN_VERIFY-UnsupportedOperationException]": { | ||
| "recorded-date": "16-07-2025, 15:59:31", | ||
| "recorded-content": {} | ||
| }, | ||
| "tests/aws/services/kms/test_kms.py::TestKMS::test_list_key_rotations_unsupported_key_types[HMAC_256-GENERATE_VERIFY_MAC-UnsupportedOperationException]": { | ||
| "recorded-date": "16-07-2025, 15:59:32", | ||
| "recorded-content": {} | ||
| }, |
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.
Are these the leftovers? Because i cant see related tests for UnsupportedOperationException specifically?
|
Hi @demaj! Thanks again for your contribution. Would you like to continue working on this PR? If you need any help to move it forward, please let me know 🙂 |
|
Hi @sannya-singal, sincere apologies, I was not able to actively work on this. I will try to find some time during this week, is it okay with you? I would love to wrap this PR up, and have my first contribution to Localstack! Thank you! 😊 |
|
No worries at all 🙂 Glad want to wrap it up, please go ahead and work on it 🎉 Excited for your first contribution! 🚀 |
Motivation
Adding support for ListKeyRotations. Mentioned in #12342.
Changes
Implementation of list-key-rotations feature for keys that may have multiple key materials associated with them.
As per AWS's, list-key-rotation is only allowed for:
TODO
What's left to do: