import boto3 import sure # noqa # pylint: disable=unused-import import pytest from cryptography.hazmat.primitives.asymmetric import rsa from unittest import mock from moto import mock_kms from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID grantee_principal = ( f"arn:aws:iam::{ACCOUNT_ID}:role/service-role/tf-acc-test-7071877926602081451" ) @mock_kms def test_create_grant(): client = boto3.client("kms", region_name="us-east-1") key_id = create_key(client) resp = client.create_grant( KeyId=key_id, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], Name="testgrant", ) resp.should.have.key("GrantId") resp.should.have.key("GrantToken") @mock_kms def test_list_grants(): client = boto3.client("kms", region_name="us-east-1") key_id = create_key(client) client.list_grants(KeyId=key_id).should.have.key("Grants").equals([]) grant_id1 = client.create_grant( KeyId=key_id, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], Name="testgrant", )["GrantId"] grant_id2 = client.create_grant( KeyId=key_id, GranteePrincipal=grantee_principal, Operations=["DECRYPT", "ENCRYPT"], Constraints={"EncryptionContextSubset": {"baz": "kaz", "foo": "bar"}}, )["GrantId"] # List all grants = client.list_grants(KeyId=key_id)["Grants"] grants.should.have.length_of(2) grant_1 = [grant for grant in grants if grant["GrantId"] == grant_id1][0] grant_2 = [grant for grant in grants if grant["GrantId"] == grant_id2][0] grant_1.should.have.key("KeyId").equals(key_id) grant_1.should.have.key("GrantId").equals(grant_id1) grant_1.should.have.key("Name").equals("testgrant") grant_1.should.have.key("GranteePrincipal").equals(grantee_principal) grant_1.should.have.key("Operations").equals(["DECRYPT"]) grant_2.should.have.key("KeyId").equals(key_id) grant_2.should.have.key("GrantId").equals(grant_id2) grant_2.shouldnt.have.key("Name") grant_2.should.have.key("GranteePrincipal").equals(grantee_principal) grant_2.should.have.key("Operations").equals(["DECRYPT", "ENCRYPT"]) grant_2.should.have.key("Constraints").equals( {"EncryptionContextSubset": {"baz": "kaz", "foo": "bar"}} ) # List by grant_id grants = client.list_grants(KeyId=key_id, GrantId=grant_id2)["Grants"] grants.should.have.length_of(1) grants[0]["GrantId"].should.equal(grant_id2) # List by unknown grant_id grants = client.list_grants(KeyId=key_id, GrantId="unknown")["Grants"] grants.should.have.length_of(0) @mock_kms def test_list_retirable_grants(): client = boto3.client("kms", region_name="us-east-1") key_id1 = create_key(client) key_id2 = create_key(client) client.create_grant( KeyId=key_id1, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], ) client.create_grant( KeyId=key_id1, GranteePrincipal=grantee_principal, RetiringPrincipal="sth else", Operations=["DECRYPT"], ) client.create_grant( KeyId=key_id2, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], ) grant2_key2 = client.create_grant( KeyId=key_id2, GranteePrincipal=grantee_principal, RetiringPrincipal="principal", Operations=["DECRYPT"], )["GrantId"] # List only the grants from the retiring principal grants = client.list_retirable_grants(RetiringPrincipal="principal")["Grants"] grants.should.have.length_of(1) grants[0]["KeyId"].should.equal(key_id2) grants[0]["GrantId"].should.equal(grant2_key2) @mock_kms def test_revoke_grant(): client = boto3.client("kms", region_name="us-east-1") key_id = create_key(client) client.list_grants(KeyId=key_id).should.have.key("Grants").equals([]) grant_id = client.create_grant( KeyId=key_id, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], Name="testgrant", )["GrantId"] client.revoke_grant(KeyId=key_id, GrantId=grant_id) client.list_grants(KeyId=key_id)["Grants"].should.have.length_of(0) @mock_kms def test_revoke_grant_raises_when_grant_does_not_exist(): client = boto3.client("kms", region_name="us-east-1") key_id = create_key(client) not_existent_grant_id = "aabbccdd" with pytest.raises(client.exceptions.NotFoundException) as ex: client.revoke_grant(KeyId=key_id, GrantId=not_existent_grant_id) ex.value.response["Error"]["Code"].should.equal("NotFoundException") ex.value.response["Error"]["Message"].should.equal( f"Grant ID {not_existent_grant_id} not found" ) @mock_kms def test_retire_grant_by_token(): client = boto3.client("kms", region_name="us-east-1") key_id = create_key(client) for idx in range(0, 3): grant_token = client.create_grant( KeyId=key_id, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], Name=f"testgrant{idx}", )["GrantToken"] client.retire_grant(GrantToken=grant_token) client.list_grants(KeyId=key_id)["Grants"].should.have.length_of(2) @mock_kms def test_retire_grant_by_grant_id(): client = boto3.client("kms", region_name="us-east-1") key_id = create_key(client) for idx in range(0, 3): grant_id = client.create_grant( KeyId=key_id, GranteePrincipal=grantee_principal, Operations=["DECRYPT"], Name=f"testgrant{idx}", )["GrantId"] client.retire_grant(KeyId=key_id, GrantId=grant_id) client.list_grants(KeyId=key_id)["Grants"].should.have.length_of(2) def create_key(client): with mock.patch.object(rsa, "generate_private_key", return_value=""): return client.create_key(Policy="my policy")["KeyMetadata"]["KeyId"]