Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions roles/aws_open_environment/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# IAM policy for the admin user created via CloudFormation.
# Default grants full access to all AWS services.
sandbox_aws_admin_user_policy:
Statement:
- Effect: Allow
Action: "*"
Resource: "*"

# Enable AWS web console access
sandbox_enable_ui: true

# Control reporting of sandbox credentials
sandbox_user_info_data_enable: true
sandbox_user_info_messages_enable: true

# Clean up Route53 hosted zones on destroy
aws_open_environment_cleanup_route53: true
15 changes: 15 additions & 0 deletions roles/aws_open_environment/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
galaxy_info:
role_name: aws_open_environment
author: Red Hat, Patrick Rutledge (prutledg@redhat.com)
description: |
Creates an IAM admin user with configurable policy in an AWS sandbox
account and reports credentials (access key, console URL) to the user.
license: MIT
min_ansible_version: "2.14"
platforms: []
galaxy_tags:
- aws
- sandbox
- openenvironment
dependencies: []
57 changes: 57 additions & 0 deletions roles/aws_open_environment/tasks/delete_route53_zone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
- name: Get all records in zone {{ _hosted_zone_id }}
ansible.builtin.command: >-
aws route53 list-resource-record-sets --hosted-zone-id {{ _hosted_zone_id }}
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key_id }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_access_key }}"
AWS_DEFAULT_REGION: "{{ aws_region | default('us-east-1') }}"
register: r_zone_records
changed_when: false

- name: Set records to delete
ansible.builtin.set_fact:
_records_to_delete: >-
{{ r_zone_records.stdout | from_json
| json_query('ResourceRecordSets')
| rejectattr('Name', 'equalto', _aws_public_zone)
| list }}

- name: Delete records and zone
when: _records_to_delete | length > 0
block:
- name: Create change batch file
ansible.builtin.copy:
dest: "{{ output_dir | default('/tmp/output_dir') }}/{{ guid }}_{{ _hosted_zone_id }}_delete_records.json"
content: |
{
"Comment": "Delete all records for {{ _hosted_zone_id }}",
"Changes": [
{% for record in _records_to_delete %}
{ "Action": "DELETE",
"ResourceRecordSet": {{ record | to_json }}
}{{ "," if not loop.last else "" }}
{% endfor %}
]
}
mode: "0644"

- name: Delete all records from the zone
ansible.builtin.command: >-
aws route53 change-resource-record-sets
--hosted-zone-id={{ _hosted_zone_id }}
--change-batch=file://{{ output_dir | default('/tmp/output_dir') }}/{{ guid }}_{{ _hosted_zone_id }}_delete_records.json
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key_id }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_access_key }}"
AWS_DEFAULT_REGION: "{{ aws_region | default('us-east-1') }}"
changed_when: true

- name: Remove hosted zone
ansible.builtin.command: >-
aws route53 delete-hosted-zone --id {{ _hosted_zone_id }}
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key_id }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_access_key }}"
AWS_DEFAULT_REGION: "{{ aws_region | default('us-east-1') }}"
changed_when: true
8 changes: 8 additions & 0 deletions roles/aws_open_environment/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- name: Running workload provision tasks
when: ACTION == "provision"
ansible.builtin.include_tasks: workload.yml

- name: Running workload removal tasks
when: ACTION == "destroy"
ansible.builtin.include_tasks: remove_workload.yml
50 changes: 50 additions & 0 deletions roles/aws_open_environment/tasks/remove_workload.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
- name: Destroy open environment CloudFormation stack
amazon.aws.cloudformation:
aws_access_key: "{{ aws_access_key_id }}"
aws_secret_key: "{{ aws_secret_access_key }}"
stack_name: "{{ project_tag }}-open-environment"
state: absent
region: "{{ aws_region_loop | default(aws_region) | default(region) | default('us-east-1') }}"
register: r_cfn_destroy
ignore_errors: true

- name: Warn if CloudFormation stack deletion failed
when: r_cfn_destroy is failed
ansible.builtin.debug:
msg: >-
WARNING: CloudFormation stack {{ project_tag }}-open-environment deletion failed.
AWS Nuke will clean up remaining resources when the sandbox is released.
Error: {{ r_cfn_destroy.msg | default('unknown') }}

- name: Clean up Route53 hosted zone
when: aws_open_environment_cleanup_route53 | default(true) | bool
block:
- name: Set public zone name
ansible.builtin.set_fact:
_aws_public_zone: "{{ guid }}.{{ subdomain_base_suffix | default(base_domain) | regex_replace('^\\.', '') }}."

- name: List hosted zones matching this environment
ansible.builtin.command: >-
aws route53 list-hosted-zones-by-name
--dns-name {{ _aws_public_zone }}
--max-items 4
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key_id }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_access_key }}"
AWS_DEFAULT_REGION: "{{ aws_region | default('us-east-1') }}"
register: r_route53_zones
changed_when: false
ignore_errors: true

- name: Delete matching hosted zones
when:
- r_route53_zones is success
- _zone.Name == _aws_public_zone
ansible.builtin.include_tasks: delete_route53_zone.yml
vars:
_hosted_zone_id: "{{ _zone.Id | regex_replace('/hostedzone/', '') }}"
loop: "{{ (r_route53_zones.stdout | from_json).HostedZones | default([]) }}"
loop_control:
loop_var: _zone
label: "{{ _zone.Name | default('unknown') }}"
67 changes: 67 additions & 0 deletions roles/aws_open_environment/tasks/workload.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
- name: Generate console password
ansible.builtin.set_fact:
aws_open_environment_console_password: >-
{{ lookup('community.general.random_string',
length=12, min_lower=1, min_upper=1, special=false, min_numeric=1) }}

- name: Deploy CloudFormation stack for open environment
amazon.aws.cloudformation:
aws_access_key: "{{ aws_access_key_id }}"
aws_secret_key: "{{ aws_secret_access_key }}"
stack_name: "{{ project_tag }}-open-environment"
state: present
region: "{{ aws_region_loop | default(aws_region) | default(region) | default('us-east-1') }}"
tags: "{{ cloud_tags_final | default(omit) }}"
template_body: "{{ lookup('template', 'open-environment.yaml.j2') }}"
register: r_cloudformation_open_env

- name: Set AWS credential facts from stack outputs
ansible.builtin.set_fact:
aws_open_environment_access_key_id: >-
{{ r_cloudformation_open_env.stack_outputs.AdminUserAccessKey }}
aws_open_environment_secret_access_key: >-
{{ r_cloudformation_open_env.stack_outputs.AdminUserSecretAccessKey }}
aws_open_environment_console_user_name: >-
{{ r_cloudformation_open_env.stack_outputs.AdminUser }}

- name: Report sandbox credentials as user info message
when: sandbox_user_info_messages_enable | default(true) | bool
agnosticd.core.agnosticd_user_info:
msg: |

Your AWS credentials are:

`AWS_ACCESS_KEY_ID: {{ aws_open_environment_access_key_id }}`

`AWS_SECRET_ACCESS_KEY: {{ aws_open_environment_secret_access_key }}`

*Please DO NOT expose these AWS credentials in GIT repos or anywhere else that could be public!*

Top level route53 domain: {{ subdomain_base_suffix | default(base_domain) }}

{% if sandbox_enable_ui | default(true) | bool %}
Web Console Access: https://{{ sandbox_account_id }}.signin.aws.amazon.com/console

Web Console Credentials: {{ aws_open_environment_console_user_name }} / {{ aws_open_environment_console_password }}
{% endif %}

- name: Report sandbox credentials as user data
when: sandbox_user_info_data_enable | default(true) | bool
agnosticd.core.agnosticd_user_info:
data:
aws_access_key_id: "{{ aws_open_environment_access_key_id }}"
aws_secret_access_key: "{{ aws_open_environment_secret_access_key }}"
aws_default_region: "{{ aws_region | default('us-east-1') }}"
aws_route53_domain: "{{ subdomain_base_suffix | default(base_domain) }}"
aws_sandbox_account_id: "{{ sandbox_account_id }}"

- name: Report web console access as user data
when:
- sandbox_user_info_data_enable | default(true) | bool
- sandbox_enable_ui | default(true) | bool
agnosticd.core.agnosticd_user_info:
data:
aws_web_console_url: "https://{{ sandbox_account_id }}.signin.aws.amazon.com/console"
aws_web_console_user_name: "{{ aws_open_environment_console_user_name }}"
aws_web_console_password: "{{ aws_open_environment_console_password }}"
36 changes: 36 additions & 0 deletions roles/aws_open_environment/templates/open-environment.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
AWSTemplateFormatVersion: "2010-09-09"
Resources:
AdminUser:
Type: AWS::IAM::User
Properties:
UserName: "{{ email | default(owner) | default('open-environment') }}-{{ guid }}-admin"
LoginProfile:
Password: {{ aws_open_environment_console_password | to_json }}
PasswordResetRequired: False
Policies:
- PolicyName: AdminAccessPolicy
PolicyDocument:
{{ sandbox_aws_admin_user_policy | to_nice_yaml | indent(12) }}

AdminUserAccessKey:
DependsOn: AdminUser
Type: AWS::IAM::AccessKey
Properties:
UserName:
Ref: AdminUser
Outputs:
AdminUser:
Value:
Ref: AdminUser
Description: IAM Admin User
AdminUserAccessKey:
Value:
Ref: AdminUserAccessKey
Description: IAM access key for Admin
AdminUserSecretAccessKey:
Value:
Fn::GetAtt:
- AdminUserAccessKey
- SecretAccessKey
Description: IAM User access key for admin
Loading