Skip to content

Commit

Permalink
Merge pull request #4 from marcelmamula/aws-fixes
Browse files Browse the repository at this point in the history
sap_vm_provision: feat: aws security enhancements
  • Loading branch information
marcelmamula authored Apr 24, 2024
2 parents 50bb742 + d556af3 commit e360e3b
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 67 deletions.
50 changes: 50 additions & 0 deletions roles/sap_vm_provision/PLATFORM_GUIDANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,56 @@ aws iam attach-group-policy --group-name 'ag-sap-automation' --policy-arn arn:aw
aws iam attach-group-policy --group-name 'ag-sap-automation' --policy-arn arn:aws:iam::aws:policy/AmazonRoute53FullAccess
```

It is recommended to create new AWS IAM Policy with detailed actions to improve security.
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ec2:DescribeImages",
"ec2:DescribeInstances",
"ec2:DescribeTags",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:RunInstances",
"ec2:CreateTags",
"ec2:DescribeInstanceStatus",
"ec2:ModifyInstanceAttribute",
"ec2:DescribeRouteTables",
"route53:ListHostedZones",
"route53:ListResourceRecordSets",
"route53:ChangeResourceRecordSets",
"route53:GetChange",
"ec2:DescribeVolumes",
"ec2:CreateVolume",
"ec2:DeleteVolume",
"ec2:AttachVolume",
"ec2:DetachVolume",
"ec2:TerminateInstances",
"ec2:CreateRoute",
"iam:GetRole",
"iam:CreateRole",
"iam:ListInstanceProfilesForRole",
"iam:CreateInstanceProfile",
"iam:AddRoleToInstanceProfile",
"iam:ListAttachedRolePolicies",
"iam:ListRoleTags",
"iam:PutRolePolicy",
"iam:GetInstanceProfile",
"iam:PassRole",
"ec2:AssociateIamInstanceProfile",
"ec2:ReplaceRoute"
],
"Resource": "*"
}
]
}
```

</details>

<details>
Expand Down
4 changes: 3 additions & 1 deletion roles/sap_vm_provision/tasks/common/set_ansible_vars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
sap_id_user_password: "{{ sap_id_user_password | default('') }}"
sap_software_download_directory: "{{ sap_software_download_directory | default('/software') }}"
sap_install_media_detect_source_directory: "{{ sap_software_download_directory | default('/software') }}"
no_log: "{{ __sap_vm_provision_no_log }}"

# - name: Set facts for all hosts - use facts from localhost - Ansible only
# ansible.builtin.set_fact:
Expand Down Expand Up @@ -47,10 +48,11 @@
sap_ha_pacemaker_cluster_aws_region: "{{ sap_ha_pacemaker_cluster_aws_region }}"
sap_ha_pacemaker_cluster_aws_access_key_id: "{{ sap_ha_pacemaker_cluster_aws_access_key_id }}"
sap_ha_pacemaker_cluster_aws_secret_access_key: "{{ sap_ha_pacemaker_cluster_aws_secret_access_key }}"
sap_ha_pacemaker_cluster_aws_vip_update_rt: "{{ aws_vpc_subnet_rt_info.route_tables[0].route_table_id }}"
sap_ha_pacemaker_cluster_aws_vip_update_rt: "{{ __sap_vm_provision_task_vpc_subnet_rt_info.route_tables[0].route_table_id }}"
when:
- sap_ha_pacemaker_cluster_aws_region is defined
- sap_vm_provision_iac_platform == "aws_ec2_vs"
no_log: "{{ __sap_vm_provision_no_log }}"

# - name: Set facts for all hosts - use facts from localhost - HA/DR - GCP
# ansible.builtin.set_fact:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@

- name: Ansible Task block for looped provisioning of AWS EC2 instances
environment:
AWS_ACCESS_KEY_ID: "{{ sap_vm_provision_aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ sap_vm_provision_aws_secret_access_key }}"
AWS_REGION: "{{ sap_vm_provision_aws_region }}"
any_errors_fatal: true
block:

- name: Identify OS Image (AWS AMI)
register: register_aws_ami
register: __sap_vm_provision_task_aws_ami
amazon.aws.ec2_ami_info:
owners: ["aws-marketplace"]
filters:
name: "{{ lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_os_image_dictionary')[sap_vm_provision_aws_ec2_vs_host_os_image] }}"
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
no_log: "{{ __sap_vm_provision_no_log }}"

- name: Set fact to hold loop variables from include_tasks
ansible.builtin.set_fact:
register_provisioned_host_all: []

- name: Provision hosts to AWS
register: register_provisioned_hosts
register: __sap_vm_provision_task_register_provisioned_hosts
ansible.builtin.include_tasks:
file: "{{ 'platform_' + sap_vm_provision_iac_type }}/{{ sap_vm_provision_iac_platform }}/execute_provision.yml"
apply:
environment:
AWS_ACCESS_KEY_ID: "{{ sap_vm_provision_aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ sap_vm_provision_aws_secret_access_key }}"
AWS_REGION: "{{ sap_vm_provision_aws_region }}"
# apply:
# environment:
# AWS_REGION: "{{ sap_vm_provision_aws_region }}"

- name: Add hosts provisioned to the Ansible Inventory
register: register_add_hosts
register: __sap_vm_provision_task_register_add_hosts
ansible.builtin.add_host:
name: "{{ add_item[0].host_node }}"
groups: "{{ add_item[0].sap_system_type + '_' if (add_item[0].sap_system_type != '') }}{{ add_item[0].sap_host_type }}"
Expand All @@ -41,7 +41,7 @@
loop_control:
label: "{{ add_item[0].host_node }}"
loop_var: add_item

no_log: "{{ __sap_vm_provision_no_log }}"

# Cannot override any variables from extravars input, see https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#understanding-variable-precedence
# Ensure no default value exists for any prompted variable before execution of Ansible Playbook
Expand All @@ -50,7 +50,10 @@
amazon.aws.ec2_vpc_route_table_info:
filters:
association.subnet-id: "{{ sap_vm_provision_aws_vpc_subnet_id }}"
register: aws_vpc_subnet_rt_info
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
register: __sap_vm_provision_task_vpc_subnet_rt_info
no_log: "{{ __sap_vm_provision_no_log }}"

- name: Set fact to hold all inventory hosts in all groups
ansible.builtin.set_fact:
Expand All @@ -71,9 +74,35 @@
ttl: 7200
value: "{{ hostvars[inventory_hostname].ansible_host }}"
wait: true

# - ansible.builtin.debug:
# var: register_add_hosts.results
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
register: __sap_vm_provision_task_route53
no_log: "{{ __sap_vm_provision_no_log }}"

rescue:
# This requires no_log set on each Ansible Task, and not set on the Ansible Task Block
# This requires an Ansible Task Block containing the Ansible Tasks for calling
# Infrastructure Platform APIs (via Ansible Modules)
- name: Show errors in task outputs
ansible.builtin.fail:
msg: "{{ lookup('ansible.builtin.vars', loop_item) }}"
loop:
- __sap_vm_provision_task_aws_ami
- __sap_vm_provision_task_provisioned_host_single
- __sap_vm_provision_task_instance_info
- __sap_vm_provision_task_volume_provisioning
- __sap_vm_provision_task_register_provisioned_hosts
- __sap_vm_provision_task_register_add_hosts
- __sap_vm_provision_task_vpc_subnet_rt_info
- __sap_vm_provision_task_route53
loop_control:
loop_var: loop_item
index_var: loop_item_index
label: "{{ 'Variable No. ' + (loop_item_index | string) }}"
when:
- lookup('ansible.builtin.vars', loop_item, default='') | length > 0
- not lookup('ansible.builtin.vars', loop_item, default='') is skipped
- lookup('ansible.builtin.vars', loop_item, default='') is failed

- name: Ansible Task block to execute on target inventory hosts
delegate_to: "{{ inventory_hostname }}"
Expand Down Expand Up @@ -120,19 +149,51 @@
delegate_to: localhost
run_once: true
environment:
AWS_ACCESS_KEY_ID: "{{ sap_vm_provision_aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ sap_vm_provision_aws_secret_access_key }}"
AWS_REGION: "{{ sap_vm_provision_aws_region }}"
when:
- sap_ha_pacemaker_cluster_aws_region is defined
- (groups["hana_secondary"] is defined and (groups["hana_secondary"] | length>0)) or (groups["nwas_ers"] is defined and (groups["nwas_ers"] | length>0)) or (groups["anydb_secondary"] is defined and (groups["anydb_secondary"] | length>0))
any_errors_fatal: true
block:

- name: Provision High Availability resources for AWS EC2 hosts
ansible.builtin.include_tasks:
file: "{{ 'platform_' + sap_vm_provision_iac_type }}/{{ sap_vm_provision_iac_platform }}/execute_setup_ha.yml"
apply:
environment:
AWS_ACCESS_KEY_ID: "{{ sap_vm_provision_aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ sap_vm_provision_aws_secret_access_key }}"
AWS_REGION: "{{ sap_vm_provision_aws_region }}"
# apply:
# environment:
# AWS_REGION: "{{ sap_vm_provision_aws_region }}"

rescue:
# This requires no_log set on each Ansible Task, and not set on the Ansible Task Block
# This requires an Ansible Task Block containing the Ansible Tasks for calling
# Infrastructure Platform APIs (via Ansible Modules)
- name: Show errors in task outputs
ansible.builtin.fail:
msg: "{{ lookup('ansible.builtin.vars', loop_item) }}"
loop:
- __sap_vm_provision_task_aws_account_info
- __sap_vm_provision_task_vpc_subnet_rt_info
- __sap_vm_provision_task_vpc_subnet_rt_route_sap_hana
- __sap_vm_provision_task_route53_sap_hana
- __sap_vm_provision_task_vpc_subnet_rt_route_sap_anydb
- __sap_vm_provision_task_route53_sap_anydb
- __sap_vm_provision_task_vpc_subnet_rt_route_sap_netweaver_ascs
- __sap_vm_provision_task_route53_sap_netweaver_ascs
- __sap_vm_provision_task_vpc_subnet_rt_route_sap_netweaver_ers
- __sap_vm_provision_task_route53_sap_netweaver_ers
- __sap_vm_provision_task_iam_role_ha_pacemaker
- __sap_vm_provision_task_iam_policy_dataprovider
- __sap_vm_provision_task_iam_policy_overlayip
- __sap_vm_provision_task_iam_policy_stonith_saphana
- __sap_vm_provision_task_iam_policy_stonith_sapnwas
- __sap_vm_provision_task_iam_attach_role
- __sap_vm_provision_task_iam_attach_instance_saphana
- __sap_vm_provision_task_iam_attach_instance_sapnwas
loop_control:
loop_var: loop_item
index_var: loop_item_index
label: "{{ 'Variable No. ' + (loop_item_index | string) }}"
when:
- lookup('ansible.builtin.vars', loop_item, default='') | length > 0
- not lookup('ansible.builtin.vars', loop_item, default='') is skipped
- lookup('ansible.builtin.vars', loop_item, default='') is failed
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
- not inventory_hostname in lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan].keys()

- name: Provision AWS EC2 Virtual Server instance
register: register_provisioned_host_single
register: __sap_vm_provision_task_provisioned_host_single
amazon.aws.ec2_instance:
state: started
name: "{{ inventory_hostname }}"
image_id: "{{ (register_aws_ami.images | sort(attribute='creation_date') | last).image_id }}"
image_id: "{{ (__sap_vm_provision_task_aws_ami.images | sort(attribute='creation_date') | last).image_id }}"
instance_type: "{{ lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].virtual_machine_profile }}"
key_name: "{{ sap_vm_provision_aws_key_pair_name_ssh_host_public_key }}"
security_groups: "{{ sap_vm_provision_aws_vpc_sg_names }}"
Expand All @@ -33,6 +33,9 @@
network:
assign_public_ip: false
source_dest_check: "{{ not lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].disable_ip_anti_spoofing }}" # Disable the Anti IP Spoofing by setting Source/Destination Check to false
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
no_log: "{{ __sap_vm_provision_no_log }}"

- name: Set fact for storage volume letters calculations (max 25 volumes)
ansible.builtin.set_fact:
Expand All @@ -43,15 +46,18 @@
filters:
"tag:Name": "{{ inventory_hostname }}"
"instance-state-name": ["running"]
register: instance_info
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
register: __sap_vm_provision_task_instance_info
no_log: "{{ __sap_vm_provision_no_log }}"

- name: Set fact for available storage volume device names
ansible.builtin.set_fact:
available_volumes: |-
{% set letters = 'bcdefghijklmnopqrstuvwxyz' %}
{% set volumes = [] %}
{%- for letter in letters -%}
{% for device in instance_info.instances[0].block_device_mappings -%}
{% for device in __sap_vm_provision_task_instance_info.instances[0].block_device_mappings -%}
{% if '/dev/sd' + letter not in device.device_name -%}
{% set dev = volumes.append('/dev/sd' + letter) %}
{%- endif %}
Expand Down Expand Up @@ -95,11 +101,13 @@
- name: Provision AWS EBS volumes for AWS EC2 Virtual Server instance filesystems
amazon.aws.ec2_vol:
name: "{{ inventory_hostname }}-vol_{{ vol_item.name }}"
instance: "{{ register_provisioned_host_single.instance_ids[0] }}"
instance: "{{ __sap_vm_provision_task_provisioned_host_single.instance_ids[0] }}"
volume_type: "{{ vol_item.type }}"
volume_size: "{{ vol_item.size }}"
device_name: "{{ vol_item.device }}"
delete_on_termination: true
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
loop: "{{ filesystem_volume_map }}"
loop_control:
loop_var: vol_item
Expand All @@ -108,26 +116,30 @@
when:
- vol_item.fstype is defined
- vol_item.size > 0
register: volume_provisioning
register: __sap_vm_provision_task_volume_provisioning
no_log: "{{ __sap_vm_provision_no_log }}"

- name: Read AWS EC2 instance information
amazon.aws.ec2_instance_info:
filters:
"tag:Name": "{{ inventory_hostname }}"
register: instance_info
access_key: "{{ sap_vm_provision_aws_access_key }}"
secret_key: "{{ sap_vm_provision_aws_secret_access_key }}"
register: __sap_vm_provision_task_instance_info
no_log: "{{ __sap_vm_provision_no_log }}"

- name: Add host facts
ansible.builtin.set_fact:
filesystem_volume_map: "{{ filesystem_volume_map }}"
volume_provisioning: "{{ volume_provisioning }}"
instance_info: "{{ instance_info }}"
__sap_vm_provision_task_volume_provisioning: "{{ __sap_vm_provision_task_volume_provisioning }}"
instance_info: "{{ __sap_vm_provision_task_instance_info }}"
delegate_to: "{{ inventory_hostname }}"
delegate_facts: true

no_log: "{{ __sap_vm_provision_no_log }}"

- name: Create fact for delegate host IP
ansible.builtin.set_fact:
provisioned_private_ip: "{{ register_provisioned_host_single.instances[0].private_ip_address }}"
provisioned_private_ip: "{{ __sap_vm_provision_task_provisioned_host_single.instances[0].private_ip_address }}"


- name: Copy facts to delegate host
Expand All @@ -139,7 +151,7 @@
delegate_sap_vm_provision_bastion_ssh_port: "{{ sap_vm_provision_bastion_ssh_port }}"
delegate_sap_vm_provision_ssh_bastion_private_key_file_path: "{{ sap_vm_provision_ssh_bastion_private_key_file_path }}"
delegate_sap_vm_provision_ssh_host_private_key_file_path: "{{ sap_vm_provision_ssh_host_private_key_file_path }}"
delegate_private_ip: "{{ register_provisioned_host_single.instances[0].private_ip_address }}"
delegate_private_ip: "{{ __sap_vm_provision_task_provisioned_host_single.instances[0].private_ip_address }}"
delegate_hostname: "{{ inventory_hostname }}"
delegate_sap_vm_provision_dns_root_domain_name: "{{ sap_vm_provision_dns_root_domain }}"

Expand Down Expand Up @@ -181,8 +193,8 @@

- name: Append loop value to register
ansible.builtin.set_fact:
register_provisioned_host_single: "{{ register_provisioned_host_single | combine( { 'host_node' : inventory_hostname } , { 'sap_host_type' : lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].sap_host_type } , { 'sap_system_type' : (lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].sap_system_type | default('')) } ) }}"
__sap_vm_provision_task_provisioned_host_single: "{{ __sap_vm_provision_task_provisioned_host_single | combine( { 'host_node' : inventory_hostname } , { 'sap_host_type' : lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].sap_host_type } , { 'sap_system_type' : (lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].sap_system_type | default('')) } ) }}"

- name: Append output to merged register
ansible.builtin.set_fact:
register_provisioned_host_all: "{{ register_provisioned_host_all + [register_provisioned_host_single] }}"
register_provisioned_host_all: "{{ register_provisioned_host_all + [__sap_vm_provision_task_provisioned_host_single] }}"
Loading

0 comments on commit e360e3b

Please sign in to comment.