mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-07 05:42:50 +00:00
Add aws_secret module for managing secretsmanager on AWS (#48486)
* Adding module for managing AWS Secrets Manager resources * adding aws_secret lookup plugin Also use the data returned by describe_secret everywhere. * replace the explicit /root use by a temporary dir * aws_secret: rework module Reworked module to use a class avoiding using client and module in every functions. * Added support of "recovery_window" parameter to allow user to provide recovery period. * updated return value to be the api output providing more details about the secret. * Fix Python 3 bug in tests if the role is not removed * Add unsupported alias due to issue restricting resource for creating secrets
This commit is contained in:
2
test/integration/targets/aws_secret/aliases
Normal file
2
test/integration/targets/aws_secret/aliases
Normal file
@@ -0,0 +1,2 @@
|
||||
cloud/aws
|
||||
unsupported
|
||||
2
test/integration/targets/aws_secret/defaults/main.yaml
Normal file
2
test/integration/targets/aws_secret/defaults/main.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
super_secret_string: 'Test12345'
|
||||
BIN
test/integration/targets/aws_secret/files/hello_world.zip
Normal file
BIN
test/integration/targets/aws_secret/files/hello_world.zip
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "lambda.amazonaws.com"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "secretsmanager.amazonaws.com"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
265
test/integration/targets/aws_secret/tasks/main.yaml
Normal file
265
test/integration/targets/aws_secret/tasks/main.yaml
Normal file
@@ -0,0 +1,265 @@
|
||||
---
|
||||
- block:
|
||||
- name: set connection information for all tasks
|
||||
set_fact:
|
||||
aws_connection_info: &aws_connection_info
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
region: "{{ aws_region }}"
|
||||
security_token: "{{ security_token }}"
|
||||
no_log: true
|
||||
|
||||
- name: retrieve caller facts
|
||||
aws_caller_facts:
|
||||
<<: *aws_connection_info
|
||||
register: test_caller_facts
|
||||
|
||||
- name: ensure IAM role exists
|
||||
iam_role:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secrets-manager-role"
|
||||
assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
|
||||
state: present
|
||||
create_instance_profile: no
|
||||
managed_policy:
|
||||
- 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
|
||||
register: iam_role_output
|
||||
ignore_errors: yes
|
||||
|
||||
# CI does not remove the role and comparing policies has a bug on Python3; fall back to use iam_role_facts
|
||||
- name: get IAM role
|
||||
iam_role_facts:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secrets-manager-role"
|
||||
when: iam_role_output is failed
|
||||
register: iam_role_facts
|
||||
|
||||
- name: set iam_role_output
|
||||
set_fact:
|
||||
iam_role_output: "{{ iam_role_facts.iam_roles[0] }}"
|
||||
when: iam_role_facts is defined
|
||||
|
||||
- name: create a temporary directory
|
||||
tempfile:
|
||||
state: directory
|
||||
register: tmp
|
||||
|
||||
- name: move lambda into place for upload
|
||||
copy:
|
||||
src: "files/hello_world.zip"
|
||||
dest: "{{ tmp.path }}/hello_world.zip"
|
||||
|
||||
- name: dummy lambda for testing
|
||||
lambda:
|
||||
<<: *aws_connection_info
|
||||
name: "hello-world-{{ resource_prefix }}"
|
||||
state: present
|
||||
zip_file: "{{ tmp.path }}/hello_world.zip"
|
||||
runtime: 'python2.7'
|
||||
role: "{{ iam_role_output.arn }}"
|
||||
handler: 'hello_world.lambda_handler'
|
||||
register: lambda_output
|
||||
until: not lambda_output.failed
|
||||
retries: 10
|
||||
delay: 5
|
||||
|
||||
- debug:
|
||||
var: lambda_output
|
||||
|
||||
# ============================================================
|
||||
# Module parameter testing
|
||||
# ============================================================
|
||||
- name: test with no parameters
|
||||
aws_secret:
|
||||
register: result
|
||||
ignore_errors: true
|
||||
check_mode: true
|
||||
|
||||
- name: assert failure when called with no parameters
|
||||
assert:
|
||||
that:
|
||||
- result.failed
|
||||
- 'result.msg.startswith("missing required arguments:")'
|
||||
|
||||
# ============================================================
|
||||
# Creation/Deletion testing
|
||||
# ============================================================
|
||||
- name: add secret to AWS Secrets Manager
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
register: result
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
- result.arn is not none
|
||||
- result.name is not none
|
||||
- result.tags is not none
|
||||
- result.version_ids_to_stages is not none
|
||||
|
||||
- name: no changes to secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
register: result
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- not result.changed
|
||||
- result.arn is not none
|
||||
|
||||
- name: make change to secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
description: 'this is a change to this secret'
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
var: result
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
- result.arn is not none
|
||||
- result.name is not none
|
||||
- result.tags is not none
|
||||
- result.version_ids_to_stages is not none
|
||||
|
||||
- name: add tags to secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
description: 'this is a change to this secret'
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
tags:
|
||||
Foo: 'Bar'
|
||||
Test: 'Tag'
|
||||
register: result
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
|
||||
- name: remove tags from secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
description: 'this is a change to this secret'
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
register: result
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
|
||||
- name: lambda policy for secrets manager
|
||||
lambda_policy:
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
function_name: "hello-world-{{ resource_prefix }}"
|
||||
statement_id: LambdaSecretsManagerTestPolicy
|
||||
action: 'lambda:InvokeFunction'
|
||||
principal: "secretsmanager.amazonaws.com"
|
||||
|
||||
- name: add rotation lambda to secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
description: 'this is a change to this secret'
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
rotation_lambda: "arn:aws:lambda:{{ aws_region }}:{{ test_caller_facts.account }}:function:hello-world-{{ resource_prefix }}"
|
||||
register: result
|
||||
retries: 100
|
||||
delay: 5
|
||||
until: not result.failed
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
|
||||
- name: remove rotation lambda from secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
description: 'this is a change to this secret'
|
||||
state: present
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
register: result
|
||||
|
||||
- name: assert correct keys are returned
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
|
||||
always:
|
||||
- name: remove secret
|
||||
aws_secret:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secret-string-{{ resource_prefix }}"
|
||||
state: absent
|
||||
secret_type: 'string'
|
||||
secret: "{{ super_secret_string }}"
|
||||
recovery_window: 0
|
||||
ignore_errors: yes
|
||||
|
||||
- name: remove lambda policy
|
||||
lambda_policy:
|
||||
<<: *aws_connection_info
|
||||
state: absent
|
||||
function_name: "hello-world-{{ resource_prefix }}"
|
||||
statement_id: lambda-secretsmanager-test-policy
|
||||
action: lambda:InvokeFunction
|
||||
principal: secretsmanager.amazonaws.com
|
||||
ignore_errors: yes
|
||||
|
||||
- name: remove dummy lambda
|
||||
lambda:
|
||||
<<: *aws_connection_info
|
||||
name: "hello-world-{{ resource_prefix }}"
|
||||
state: absent
|
||||
zip_file: "{{ tmp.path }}/hello_world.zip"
|
||||
runtime: 'python2.7'
|
||||
role: "test-secrets-manager-role"
|
||||
handler: 'hello_world.lambda_handler'
|
||||
ignore_errors: yes
|
||||
|
||||
# CI does not remove the IAM role
|
||||
- name: remove IAM role
|
||||
iam_role:
|
||||
<<: *aws_connection_info
|
||||
name: "test-secrets-manager-role"
|
||||
assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
|
||||
state: absent
|
||||
create_instance_profile: no
|
||||
managed_policy:
|
||||
- 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
|
||||
ignore_errors: yes
|
||||
|
||||
- name: remove temporary dir
|
||||
file:
|
||||
path: "{{ tmp.path }}"
|
||||
state: absent
|
||||
Reference in New Issue
Block a user