From 348dc54e6a93b9cd71995f2134cd58c2eb8d23ba Mon Sep 17 00:00:00 2001 From: Jack Danger Date: Wed, 24 Jul 2019 19:15:43 -0700 Subject: [PATCH] Supporting tags in KMS (#2332) The CreateKey API method accepts tags but does not return them. --- moto/kms/models.py | 13 ++++---- moto/kms/responses.py | 3 +- moto/resourcegroupstaggingapi/models.py | 28 ++++++++++++++--- tests/test_kms/test_kms.py | 18 +++++++---- .../test_resourcegroupstaggingapi.py | 30 +++++++++++++++---- 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/moto/kms/models.py b/moto/kms/models.py index 2d6245ad2..577840b06 100644 --- a/moto/kms/models.py +++ b/moto/kms/models.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import os import boto.kms from moto.core import BaseBackend, BaseModel -from moto.core.utils import iso_8601_datetime_without_milliseconds, unix_time +from moto.core.utils import iso_8601_datetime_without_milliseconds from .utils import generate_key_id from collections import defaultdict from datetime import datetime, timedelta @@ -11,7 +11,7 @@ from datetime import datetime, timedelta class Key(BaseModel): - def __init__(self, policy, key_usage, description, region): + def __init__(self, policy, key_usage, description, tags, region): self.id = generate_key_id() self.policy = policy self.key_usage = key_usage @@ -22,7 +22,7 @@ class Key(BaseModel): self.account_id = "0123456789012" self.key_rotation_status = False self.deletion_date = None - self.tags = {} + self.tags = tags or {} @property def physical_resource_id(self): @@ -37,7 +37,7 @@ class Key(BaseModel): "KeyMetadata": { "AWSAccountId": self.account_id, "Arn": self.arn, - "CreationDate": "%d" % unix_time(), + "CreationDate": iso_8601_datetime_without_milliseconds(datetime.now()), "Description": self.description, "Enabled": self.enabled, "KeyId": self.id, @@ -61,6 +61,7 @@ class Key(BaseModel): policy=properties['KeyPolicy'], key_usage='ENCRYPT_DECRYPT', description=properties['Description'], + tags=properties.get('Tags'), region=region_name, ) key.key_rotation_status = properties['EnableKeyRotation'] @@ -80,8 +81,8 @@ class KmsBackend(BaseBackend): self.keys = {} self.key_to_aliases = defaultdict(set) - def create_key(self, policy, key_usage, description, region): - key = Key(policy, key_usage, description, region) + def create_key(self, policy, key_usage, description, tags, region): + key = Key(policy, key_usage, description, tags, region) self.keys[key.id] = key return key diff --git a/moto/kms/responses.py b/moto/kms/responses.py index 92195ed6b..8cd6e7663 100644 --- a/moto/kms/responses.py +++ b/moto/kms/responses.py @@ -31,9 +31,10 @@ class KmsResponse(BaseResponse): policy = self.parameters.get('Policy') key_usage = self.parameters.get('KeyUsage') description = self.parameters.get('Description') + tags = self.parameters.get('Tags') key = self.kms_backend.create_key( - policy, key_usage, description, self.region) + policy, key_usage, description, tags, self.region) return json.dumps(key.to_dict()) def update_key_description(self): diff --git a/moto/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py index 4aec63aa6..3f15017cc 100644 --- a/moto/resourcegroupstaggingapi/models.py +++ b/moto/resourcegroupstaggingapi/models.py @@ -10,6 +10,7 @@ from moto.ec2 import ec2_backends from moto.elb import elb_backends from moto.elbv2 import elbv2_backends from moto.kinesis import kinesis_backends +from moto.kms import kms_backends from moto.rds2 import rds2_backends from moto.glacier import glacier_backends from moto.redshift import redshift_backends @@ -71,6 +72,13 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): """ return kinesis_backends[self.region_name] + @property + def kms_backend(self): + """ + :rtype: moto.kms.models.KmsBackend + """ + return kms_backends[self.region_name] + @property def rds_backend(self): """ @@ -221,9 +229,6 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): if not resource_type_filters or 'elasticloadbalancer' in resource_type_filters or 'elasticloadbalancer:loadbalancer' in resource_type_filters: for elb in self.elbv2_backend.load_balancers.values(): tags = get_elbv2_tags(elb.arn) - # if 'elasticloadbalancer:loadbalancer' in resource_type_filters: - # from IPython import embed - # embed() if not tag_filter(tags): # Skip if no tags, or invalid filter continue @@ -235,6 +240,21 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): # Kinesis + # KMS + def get_kms_tags(kms_key_id): + result = [] + for tag in self.kms_backend.list_resource_tags(kms_key_id): + result.append({'Key': tag['TagKey'], 'Value': tag['TagValue']}) + return result + + if not resource_type_filters or 'kms' in resource_type_filters: + for kms_key in self.kms_backend.list_keys(): + tags = get_kms_tags(kms_key.id) + if not tag_filter(tags): # Skip if no tags, or invalid filter + continue + + yield {'ResourceARN': '{0}'.format(kms_key.arn), 'Tags': tags} + # RDS Instance # RDS Reserved Database Instance # RDS Option Group @@ -370,7 +390,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): def get_resources(self, pagination_token=None, resources_per_page=50, tags_per_page=100, tag_filters=None, resource_type_filters=None): - # Simple range checning + # Simple range checking if 100 >= tags_per_page >= 500: raise RESTError('InvalidParameterException', 'TagsPerPage must be between 100 and 500') if 1 >= resources_per_page >= 50: diff --git a/tests/test_kms/test_kms.py b/tests/test_kms/test_kms.py index f0d77d3e9..8fe0620f1 100644 --- a/tests/test_kms/test_kms.py +++ b/tests/test_kms/test_kms.py @@ -11,21 +11,29 @@ import sure # noqa from moto import mock_kms, mock_kms_deprecated from nose.tools import assert_raises from freezegun import freeze_time +from datetime import date from datetime import datetime from dateutil.tz import tzutc -@mock_kms_deprecated +@mock_kms def test_create_key(): - conn = boto.kms.connect_to_region("us-west-2") + conn = boto3.client('kms', region_name='us-east-1') with freeze_time("2015-01-01 00:00:00"): - key = conn.create_key(policy="my policy", - description="my key", key_usage='ENCRYPT_DECRYPT') + key = conn.create_key(Policy="my policy", + Description="my key", + KeyUsage='ENCRYPT_DECRYPT', + Tags=[ + { + 'TagKey': 'project', + 'TagValue': 'moto', + }, + ]) key['KeyMetadata']['Description'].should.equal("my key") key['KeyMetadata']['KeyUsage'].should.equal("ENCRYPT_DECRYPT") key['KeyMetadata']['Enabled'].should.equal(True) - key['KeyMetadata']['CreationDate'].should.equal("1420070400") + key['KeyMetadata']['CreationDate'].should.be.a(date) @mock_kms_deprecated diff --git a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py index 8015472bf..1e42dfe55 100644 --- a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py +++ b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py @@ -2,7 +2,11 @@ from __future__ import unicode_literals import boto3 import sure # noqa -from moto import mock_resourcegroupstaggingapi, mock_s3, mock_ec2, mock_elbv2 +from moto import mock_ec2 +from moto import mock_elbv2 +from moto import mock_kms +from moto import mock_resourcegroupstaggingapi +from moto import mock_s3 @mock_s3 @@ -225,10 +229,12 @@ def test_get_tag_values_ec2(): @mock_ec2 @mock_elbv2 +@mock_kms @mock_resourcegroupstaggingapi -def test_get_resources_elbv2(): - conn = boto3.client('elbv2', region_name='us-east-1') +def test_get_many_resources(): + elbv2 = boto3.client('elbv2', region_name='us-east-1') ec2 = boto3.resource('ec2', region_name='us-east-1') + kms = boto3.client('kms', region_name='us-east-1') security_group = ec2.create_security_group( GroupName='a-security-group', Description='First One') @@ -242,7 +248,7 @@ def test_get_resources_elbv2(): CidrBlock='172.28.7.0/26', AvailabilityZone='us-east-1b') - conn.create_load_balancer( + elbv2.create_load_balancer( Name='my-lb', Subnets=[subnet1.id, subnet2.id], SecurityGroups=[security_group.id], @@ -259,13 +265,27 @@ def test_get_resources_elbv2(): ] ) - conn.create_load_balancer( + elbv2.create_load_balancer( Name='my-other-lb', Subnets=[subnet1.id, subnet2.id], SecurityGroups=[security_group.id], Scheme='internal', ) + kms.create_key( + KeyUsage='ENCRYPT_DECRYPT', + Tags=[ + { + 'TagKey': 'key_name', + 'TagValue': 'a_value' + }, + { + 'TagKey': 'key_2', + 'TagValue': 'val2' + } + ] + ) + rtapi = boto3.client('resourcegroupstaggingapi', region_name='us-east-1') resp = rtapi.get_resources(ResourceTypeFilters=['elasticloadbalancer:loadbalancer'])