diff --git a/changelogs/fragments/20230424-config-delivery-channel.yml b/changelogs/fragments/20230424-config-delivery-channel.yml new file mode 100644 index 00000000000..819bcc42edb --- /dev/null +++ b/changelogs/fragments/20230424-config-delivery-channel.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - aws_config_delivery_channel - add support for encrypted objects in S3 via KMS key (https://github.com/ansible-collections/community.aws/pull/1786). diff --git a/plugins/modules/config_delivery_channel.py b/plugins/modules/config_delivery_channel.py index aae8799de20..dc03a95f719 100644 --- a/plugins/modules/config_delivery_channel.py +++ b/plugins/modules/config_delivery_channel.py @@ -36,6 +36,10 @@ description: - The prefix for the specified Amazon S3 bucket. type: str + kms_key_arn: + description: + - The ARN of a KMS key used to encrypt objects delivered by Config. The key must belong to the same region as the destination S3 bucket. + type: str sns_topic_arn: description: - The Amazon Resource Name (ARN) of the Amazon SNS topic to which AWS Config sends notifications about configuration changes. @@ -52,11 +56,20 @@ """ EXAMPLES = r""" -- name: Create Delivery Channel for AWS Config +- name: Create a delivery channel for AWS Config + community.aws.config_delivery_channel: + name: test_delivery_channel + state: present + s3_bucket: 'test_aws_config_bucket' + sns_topic_arn: 'arn:aws:sns:us-east-1:123456789012:aws_config_topic:1234ab56-cdef-7g89-01hi-2jk34l5m67no' + delivery_frequency: 'Twelve_Hours' + +- name: Create a delivery channel with encrypted objects community.aws.config_delivery_channel: name: test_delivery_channel state: present s3_bucket: 'test_aws_config_bucket' + kms_key_arn: 'arn:aws:kms:us-east-1:123456789012:key/160f41cb-e660-4fa0-8bf6-976f53bf7851' sns_topic_arn: 'arn:aws:sns:us-east-1:123456789012:aws_config_topic:1234ab56-cdef-7g89-01hi-2jk34l5m67no' delivery_frequency: 'Twelve_Hours' """ @@ -177,6 +190,7 @@ def main(): "state": dict(type="str", choices=["present", "absent"], default="present"), "s3_bucket": dict(type="str", required=True), "s3_prefix": dict(type="str"), + "kms_key_arn": dict(type="str", no_log=True), "sns_topic_arn": dict(type="str"), "delivery_frequency": dict( type="str", @@ -204,6 +218,8 @@ def main(): params["s3BucketName"] = module.params.get("s3_bucket") if module.params.get("s3_prefix"): params["s3KeyPrefix"] = module.params.get("s3_prefix") + if module.params.get("kms_key_arn"): + params["s3KmsKeyArn"] = module.params.get("kms_key_arn") if module.params.get("sns_topic_arn"): params["snsTopicARN"] = module.params.get("sns_topic_arn") if module.params.get("delivery_frequency"): diff --git a/tests/integration/targets/config/defaults/main.yaml b/tests/integration/targets/config/defaults/main.yaml index 26b39c58346..3beeca841b6 100644 --- a/tests/integration/targets/config/defaults/main.yaml +++ b/tests/integration/targets/config/defaults/main.yaml @@ -1,4 +1,5 @@ --- config_s3_bucket: '{{ resource_prefix }}-config-records' +config_kms_key: '{{ resource_prefix }}-kms' config_sns_name: '{{ resource_prefix }}-delivery-channel-test-topic' config_role_name: 'ansible-test-{{ resource_prefix }}' diff --git a/tests/integration/targets/config/tasks/main.yaml b/tests/integration/targets/config/tasks/main.yaml index 313f9f6770e..8c7f0208855 100644 --- a/tests/integration/targets/config/tasks/main.yaml +++ b/tests/integration/targets/config/tasks/main.yaml @@ -13,6 +13,13 @@ # ============================================================ # Prerequisites # ============================================================ + - name: get ARN of calling user + aws_caller_info: + register: aws_caller_info + + - name: Store Account ID for later use + set_fact: + aws_account_id: "{{ aws_caller_info.account }}" - name: ensure IAM role exists iam_role: @@ -21,7 +28,7 @@ state: present create_instance_profile: no managed_policy: - - 'arn:aws:iam::aws:policy/service-role/AWSConfigRole' + - arn:aws:iam::aws:policy/service-role/AWS_ConfigRole register: config_iam_role - name: ensure SNS topic exists @@ -37,6 +44,12 @@ s3_bucket: name: "{{ config_s3_bucket }}" + - name: ensure KMS key exists + kms_key: + alias: "{{ config_kms_key }}" + policy: "{{ lookup('template', 'config-kms-policy.json.j2') }}" + register: kms_key + - name: ensure S3 access for IAM role iam_policy: iam_type: role @@ -184,6 +197,21 @@ that: - output.changed + - name: Create Delivery Channel for AWS Config with a KMS key + aws_config_delivery_channel: + name: '{{ resource_prefix }}-channel' + state: present + s3_bucket: "{{ config_s3_bucket }}" + s3_prefix: "foo/bar" + kms_key_arn: "{{ kms_key.key_arn }}" + sns_topic_arn: "{{ config_sns_topic.sns_arn }}" + delivery_frequency: 'Twelve_Hours' + register: output + + - assert: + that: + - output.changed + - name: Create Config Rule for AWS Config aws_config_rule: name: '{{ resource_prefix }}-rule' @@ -263,6 +291,20 @@ that: - output.changed + - name: Update Delivery Channel with KMS key + aws_config_delivery_channel: + name: '{{ resource_prefix }}-channel' + state: present + s3_bucket: "{{ config_s3_bucket }}" + sns_topic_arn: "{{ config_sns_topic.sns_arn }}" + kms_key_arn: "{{ kms_key.key_arn }}" + delivery_frequency: 'TwentyFour_Hours' + register: output + + - assert: + that: + - output.changed + - name: Update Config Rule aws_config_rule: name: '{{ resource_prefix }}-rule' @@ -397,7 +439,7 @@ name: '{{ resource_prefix }}-recorder' state: absent register: output - ignore_errors: yes + ignore_errors: true # - assert: # that: @@ -411,7 +453,7 @@ sns_topic_arn: "{{ config_sns_topic.sns_arn }}" delivery_frequency: 'TwentyFour_Hours' register: output - ignore_errors: yes + ignore_errors: true # - assert: # that: @@ -429,7 +471,7 @@ owner: AWS identifier: 'S3_BUCKET_PUBLIC_READ_PROHIBITED' register: output - ignore_errors: yes + ignore_errors: true # - assert: # that: @@ -445,23 +487,29 @@ policy_name: AwsConfigRecorderTestRoleS3Policy state: absent policy_json: "{{ lookup( 'template', 'config-s3-policy.json.j2') }}" - ignore_errors: yes + ignore_errors: true - name: remove IAM role iam_role: name: '{{ config_role_name }}' state: absent - ignore_errors: yes + ignore_errors: true - name: remove SNS topic sns_topic: name: '{{ config_sns_name }}' state: absent - ignore_errors: yes + ignore_errors: true - name: remove S3 bucket s3_bucket: name: "{{ config_s3_bucket }}" state: absent - force: yes - ignore_errors: yes + force: true + ignore_errors: true + + - name: remove KMS key + kms_key: + alias: "{{ config_kms_key }}" + state: absent + ignore_errors: true diff --git a/tests/integration/targets/config/templates/config-kms-policy.json.j2 b/tests/integration/targets/config/templates/config-kms-policy.json.j2 new file mode 100644 index 00000000000..260adc8391b --- /dev/null +++ b/tests/integration/targets/config/templates/config-kms-policy.json.j2 @@ -0,0 +1,51 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Enable IAM User Permissions", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::{{ aws_account_id }}:root" + }, + "Action": "kms:*", + "Resource": "*" + }, + { + "Sid": "Allow use of the key", + "Effect": "Allow", + "Principal": { + "AWS": [ + "arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + ] + }, + "Action": [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey" + ], + "Resource": "*" + }, + { + "Sid": "Allow attachment of persistent resources", + "Effect": "Allow", + "Principal": { + "AWS": [ + "arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + ] + }, + "Action": [ + "kms:CreateGrant", + "kms:ListGrants", + "kms:RevokeGrant" + ], + "Resource": "*", + "Condition": { + "Bool": { + "kms:GrantIsForAWSResource": "true" + } + } + } + ] +} \ No newline at end of file