mirror of https://github.com/ansible/ansible.git
aws_kms enhancements (#31960)
* Allow creation and deletion of keys (deletion just schedules for deletion, recreating an old key is just cancelling its deletion) * Allow grants to be set, thus enabling encryption contexts to be used with keys * Allow tags to be added and modified * Add testing for KMS module * Tidy up aws_kms module to latest standardspull/52142/head
parent
1f3a74c0c8
commit
46fbcf08bc
@ -0,0 +1,2 @@
|
||||
minor_changes:
|
||||
- aws_kms is now able to create keys and manage grants and tags
|
@ -0,0 +1,54 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AllowAccessToUnspecifiedKMSResources",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"iam:ListRoles",
|
||||
"kms:CancelKeyDeletion",
|
||||
"kms:CreateAlias",
|
||||
"kms:CreateGrant",
|
||||
"kms:CreateKey",
|
||||
"kms:DeleteAlias",
|
||||
"kms:Describe*",
|
||||
"kms:DisableKey",
|
||||
"kms:EnableKey",
|
||||
"kms:GenerateRandom",
|
||||
"kms:Get*",
|
||||
"kms:List*",
|
||||
"kms:RetireGrant",
|
||||
"kms:ScheduleKeyDeletion",
|
||||
"kms:TagResource",
|
||||
"kms:UntagResource",
|
||||
"kms:UpdateGrant",
|
||||
"kms:UpdateKeyDescription"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "AllowAccessToSpecifiedIAMResources",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"iam:CreateRole",
|
||||
"iam:DeleteRole",
|
||||
"iam:GetRole",
|
||||
"iam:ListAttachedRolePolicies",
|
||||
"iam:ListInstanceProfilesForRole",
|
||||
"iam:PassRole",
|
||||
"iam:UpdateAssumeRolePolicy"
|
||||
],
|
||||
"Resource": "arn:aws:iam::{{aws_account}}:role/ansible-test-*"
|
||||
},
|
||||
{
|
||||
"Sid": "AllowInstanceProfileCreation",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"iam:AddRoleToInstanceProfile",
|
||||
"iam:CreateInstanceProfile",
|
||||
"iam:RemoveRoleFromInstanceProfile"
|
||||
],
|
||||
"Resource": "arn:aws:iam::{{aws_account}}:instance-profile/ansible-test-*"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
cloud/aws
|
||||
aws_kms_facts
|
||||
unsupported
|
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- prepare_tests
|
||||
- setup_ec2
|
@ -0,0 +1,394 @@
|
||||
- block:
|
||||
|
||||
# ============================================================
|
||||
- name: See whether key exists and its current state
|
||||
aws_kms_facts:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
filters:
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
|
||||
- name: create a key
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
enabled: yes
|
||||
register: create_kms
|
||||
|
||||
- name: assert that state is enabled
|
||||
assert:
|
||||
that:
|
||||
- create_kms.key_state == "Enabled"
|
||||
|
||||
- name: find facts about the key
|
||||
aws_kms_facts:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
filters:
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
register: new_key
|
||||
|
||||
- name: check that a key was found
|
||||
assert:
|
||||
that:
|
||||
- new_key["keys"]|length == 1
|
||||
|
||||
- name: create an IAM role that can do nothing
|
||||
iam_role:
|
||||
name: "{{ resource_prefix }}-kms-role"
|
||||
state: present
|
||||
assume_role_policy_document: '{"Version": "2012-10-17", "Statement": {"Action": "sts:AssumeRole", "Principal": {"Service": "ec2.amazonaws.com"}, "Effect": "Deny"} }'
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
register: iam_role_result
|
||||
|
||||
- name: grant user-style access to production secrets
|
||||
aws_kms:
|
||||
mode: grant
|
||||
key_alias: "alias/{{ resource_prefix }}-kms"
|
||||
role_name: "{{ resource_prefix }}-kms-role"
|
||||
grant_types: "role,role grant"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
region: "{{ aws_region }}"
|
||||
|
||||
- name: find facts about the key
|
||||
aws_kms_facts:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
filters:
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
register: new_key
|
||||
|
||||
- name: remove access to production secrets from role
|
||||
aws_kms:
|
||||
mode: deny
|
||||
key_alias: "alias/{{ resource_prefix }}-kms"
|
||||
role_arn: "{{ iam_role_result.iam_role.arn }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
region: "{{ aws_region }}"
|
||||
|
||||
- name: find facts about the key
|
||||
aws_kms_facts:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
filters:
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
register: new_key
|
||||
|
||||
- fail:
|
||||
|
||||
- name: set aws environment base fact
|
||||
set_fact:
|
||||
aws_environment_base:
|
||||
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||
no_log: True
|
||||
|
||||
- name: set aws environment fact
|
||||
set_fact:
|
||||
aws_environment: "{{ aws_environment_base|combine(security_token|ternary({'AWS_SECURITY_TOKEN': security_token}, {})) }}"
|
||||
no_log: True
|
||||
|
||||
- name: get ARN of calling user
|
||||
command: python -c 'import boto3,json; sts = boto3.client("sts"); print json.dumps(sts.get_caller_identity())'
|
||||
changed_when: False
|
||||
environment: "{{ aws_environment }}"
|
||||
register: sts_get_caller_results
|
||||
|
||||
- name: set caller_arn
|
||||
set_fact:
|
||||
caller_arn: "{{ (sts_get_caller_results.stdout|from_json).Arn }}"
|
||||
|
||||
- name: Allow the IAM role to use a specific Encryption Context
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
purge_grants: yes
|
||||
purge_tags: yes
|
||||
grants:
|
||||
- name: test_grant
|
||||
grantee_principal: "{{ iam_role_result.iam_role.arn }}"
|
||||
retiring_principal: "{{ caller_arn }}"
|
||||
constraints:
|
||||
encryption_context_equals:
|
||||
environment: test
|
||||
application: testapp
|
||||
operations:
|
||||
- Decrypt
|
||||
- RetireGrant
|
||||
register: grant_one
|
||||
|
||||
- name: assert grant added
|
||||
assert:
|
||||
that:
|
||||
- grant_one.changed
|
||||
- grant_one.grants|length == 1
|
||||
|
||||
- name: Add a second grant
|
||||
kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
grants:
|
||||
- name: another_grant
|
||||
grantee_principal: "{{ iam_role_result.iam_role.arn }}"
|
||||
retiring_principal: "{{ caller_arn }}"
|
||||
constraints:
|
||||
encryption_context_equals:
|
||||
Environment: second
|
||||
Application: anotherapp
|
||||
operations:
|
||||
- Decrypt
|
||||
- RetireGrant
|
||||
register: grant_two
|
||||
|
||||
- name: assert grant added
|
||||
assert:
|
||||
that:
|
||||
- grant_two.changed
|
||||
- grant_two.grants|length == 2
|
||||
|
||||
- name: Add a second grant again
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
grants:
|
||||
- name: another_grant
|
||||
grantee_principal: "{{ iam_role_result.iam_role.arn }}"
|
||||
retiring_principal: "{{ caller_arn }}"
|
||||
constraints:
|
||||
encryption_context_equals:
|
||||
Environment: second
|
||||
Application: anotherapp
|
||||
operations:
|
||||
- Decrypt
|
||||
- RetireGrant
|
||||
register: grant_two_again
|
||||
|
||||
- name: assert grant added
|
||||
assert:
|
||||
that:
|
||||
- not grant_two_again.changed
|
||||
- grant_two_again.grants|length == 2
|
||||
|
||||
- name: Update the grants with purge_grants set
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
purge_grants: yes
|
||||
grants:
|
||||
- name: third_grant
|
||||
grantee_principal: "{{ iam_role_result.iam_role.arn }}"
|
||||
retiring_principal: "{{ caller_arn }}"
|
||||
constraints:
|
||||
encryption_context_equals:
|
||||
environment: third
|
||||
application: onemoreapp
|
||||
operations:
|
||||
- Decrypt
|
||||
- RetireGrant
|
||||
register: grant_three
|
||||
|
||||
- name: assert grants replaced
|
||||
assert:
|
||||
that:
|
||||
- grant_three.changed
|
||||
- grant_three.grants|length == 1
|
||||
|
||||
- name: update third grant to change encryption context equals to subset
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
grants:
|
||||
- name: third_grant
|
||||
grantee_principal: "{{ iam_role_result.iam_role.arn }}"
|
||||
retiring_principal: "{{ caller_arn }}"
|
||||
constraints:
|
||||
encryption_context_subset:
|
||||
environment: third
|
||||
application: onemoreapp
|
||||
operations:
|
||||
- Decrypt
|
||||
- RetireGrant
|
||||
register: grant_three_update
|
||||
|
||||
- name: assert grants replaced
|
||||
assert:
|
||||
that:
|
||||
- "grant_three_update.changed"
|
||||
- "grant_three_update.grants|length == 1"
|
||||
- "'encryption_context_equals' not in grant_three_update.grants[0].constraints"
|
||||
- "'encryption_context_subset' in grant_three_update.grants[0].constraints"
|
||||
|
||||
- name: tag encryption key
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
tags:
|
||||
tag_one: tag_one
|
||||
tag_two: tag_two
|
||||
register: tag_kms
|
||||
|
||||
- name: assert tags added and grants remain in place
|
||||
assert:
|
||||
that:
|
||||
- "tag_kms.changed"
|
||||
- "tag_kms.grants|length == 1"
|
||||
- "'tag_one' in tag_kms.tags"
|
||||
- "'tag_two' in tag_kms.tags"
|
||||
|
||||
- name: add, replace, remove tags
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
purge_tags: yes
|
||||
tags:
|
||||
tag_two: tag_two_updated
|
||||
tag_three: tag_three
|
||||
register: tag_kms_update
|
||||
|
||||
- name: assert tags correctly changed
|
||||
assert:
|
||||
that:
|
||||
- "tag_kms_update.changed"
|
||||
- "'tag_one' not in tag_kms_update.tags"
|
||||
- "'tag_two' in tag_kms_update.tags"
|
||||
- "tag_kms_update.tags.tag_two == 'tag_two_updated'"
|
||||
- "'tag_three' in tag_kms_update.tags"
|
||||
|
||||
- name: make no real tag change
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
register: tag_kms_no_update
|
||||
|
||||
- name: assert no change to tags
|
||||
assert:
|
||||
that:
|
||||
- "not tag_kms_no_update.changed"
|
||||
- "'tag_one' not in tag_kms_no_update.tags"
|
||||
- "'tag_two' in tag_kms_no_update.tags"
|
||||
- "tag_kms_no_update.tags.tag_two == 'tag_two_updated'"
|
||||
- "'tag_three' in tag_kms_no_update.tags"
|
||||
|
||||
- name: update the key's description and disable it
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
description: test key for testing
|
||||
enabled: no
|
||||
register: update_key
|
||||
|
||||
- name: assert that state is enabled
|
||||
assert:
|
||||
that:
|
||||
- update_key.description == "test key for testing"
|
||||
- update_key.key_state == "Disabled"
|
||||
- update_key.changed
|
||||
|
||||
- name: delete the key
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: absent
|
||||
register: delete_kms
|
||||
|
||||
- name: assert that state is pending deletion
|
||||
assert:
|
||||
that:
|
||||
- delete_kms.key_state == "PendingDeletion"
|
||||
- delete_kms.changed
|
||||
|
||||
- name: undelete and enable the key
|
||||
aws_kms:
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
state: present
|
||||
enabled: yes
|
||||
register: undelete_kms
|
||||
|
||||
- name: assert that state is enabled
|
||||
assert:
|
||||
that:
|
||||
- undelete_kms.key_state == "Enabled"
|
||||
- undelete_kms.changed
|
||||
|
||||
always:
|
||||
|
||||
# ============================================================
|
||||
- name: finish off by deleting key
|
||||
aws_kms:
|
||||
state: absent
|
||||
region: "{{ aws_region }}"
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
alias: "{{ resource_prefix }}-kms"
|
||||
register: destroy_result
|
||||
|
||||
- name: remove the IAM role
|
||||
iam_role:
|
||||
name: "{{ resource_prefix }}-kms-role"
|
||||
state: absent
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
register: iam_role_result
|
Loading…
Reference in New Issue