ansible / awx

AWX provides a web-based user interface, REST API, and task engine built on top of Ansible. It is one of the upstream projects for Red Hat Ansible Automation Platform.
Other
13.86k stars 3.4k forks source link

aws_ec2 plugin in AWX Unable to assume IAM role #12394

Open mihai-satmarean opened 2 years ago

mihai-satmarean commented 2 years ago

Please confirm the following

Bug Summary

While using the aws_ec2 plugin with AWX the assume role does not work as expected, but it works from a control machine command line with minimal configuration

AWX version

21.0.0

Select the relevant components

Installation method

kubernetes

Modifications

no

Ansible version

core 2.12.5.post0

Operating system

rocky 8

Web browser

Safari

Steps to reproduce

the AWX is configured automatically by means of passing a variable file to an Ansible playbook that calls the API of AWX.

the inventory section of code looks like this:

    source_vars:
      compose:
        ansible_host: private_ip_address
        ec2_account_id: owner_id
        ec2_ami_launch_index: ami_launch_index | string
        ec2_architecture: architecture
        ec2_block_devices: dict(block_device_mappings | map(attribute='device_name') | list
          | zip(block_device_mappings | map(attribute='ebs.volume_id') | list))
        ec2_client_token: client_token
        ec2_dns_name: public_dns_name
        ec2_ebs_optimized: ebs_optimized
        ec2_eventsSet: events | default("")
        ec2_group_name: placement.group_name
        ec2_hypervisor: hypervisor
        ec2_id: instance_id
        ec2_image_id: image_id
        ec2_instance_profile: iam_instance_profile | default("")
        ec2_instance_type: instance_type
        ec2_ip_address: public_ip_address
        ec2_kernel: kernel_id | default("")
        ec2_key_name: key_name
        ec2_launch_time: launch_time | regex_replace(" ", "T") | regex_replace("(\+)(\d\d):(\d)(\d)$",
          ".\g<2>\g<3>Z")
        ec2_monitored: monitoring.state in ['enabled', 'pending']
        ec2_monitoring_state: monitoring.state
        ec2_persistent: persistent | default(false)
        ec2_placement: placement.availability_zone
        ec2_platform: platform | default("")
        ec2_private_dns_name: private_dns_name
        ec2_private_ip_address: private_ip_address
        ec2_public_dns_name: public_dns_name
        ec2_ramdisk: ramdisk_id | default("")
        ec2_reason: state_transition_reason
        ec2_region: placement.region
        ec2_requester_id: requester_id | default("")
        ec2_root_device_name: root_device_name
        ec2_root_device_type: root_device_type
        ec2_security_group_ids: security_groups | map(attribute='group_id') | list |  join(',')
        ec2_security_group_names: security_groups | map(attribute='group_name') | list |  join(',')
        ec2_sourceDestCheck: source_dest_check | default(false) | lower | string
        ec2_spot_instance_request_id: spot_instance_request_id | default("")
        ec2_state: state.name
        ec2_state_code: state.code
        ec2_state_reason: state_reason.message if state_reason is defined else ""
        ec2_subnet_id: subnet_id | default("")
        ec2_tag_Name: tags.Name
        ec2_virtualization_type: virtualization_type
        ec2_vpc_id: vpc_id | default("")
      filters: {}
      groups:
        ec2: true
      hostnames:
      - network-interface.addresses.private-ip-address
      - network-interface.addresses.association.public-ip
      - dns-name
      - private-dns-name
      keyed_groups:
      - key: dict(tags.keys() | map("regex_replace", "[^A-Za-z0-9\_]", "_") | list | zip(tags.values()
          | map("regex_replace", "[^A-Za-z0-9\_]", "_") | list))
        parent_group: tags
        prefix: tag
      - key: tags.keys() | map("regex_replace", "[^A-Za-z0-9\_]", "_") | list
        parent_group: tags
        prefix: tag
      plugin: amazon.aws.aws_ec2
      iam_role_arn: arn:aws:iam::<someid>:role/OrganizationAccountAccessRole
      use_contrib_script_compatible_sanitization: true

Expected results

the inventory of the assumed account is retrieved

Actual results

No config file found; using defaults
redirecting (type: inventory) ansible.builtin.aws_ec2 to amazon.aws.aws_ec2
[WARNING]:  * Failed to parse /runner/inventory/aws_ec2.yml with auto plugin:
Unable to assume IAM role: An error occurred (AccessDenied) when calling the
AssumeRole operation: User: arn:aws:iam::<someid>:user/someuser is
not authorized to perform: sts:AssumeRole on resource:
arn:aws:iam::<someid<:role/OrganizationAccountAccessRole

Additional information

the same block of code when used in an inventory file and called like this:

ansible-inventory -i inventory.aws_ec2.yml --list

produces the listing of the hosts on the assumed account inventory.

Any hint appreciated.

mihai-satmarean commented 2 years ago

maybe is an error or something wrong configured in the AWS, but when using accounts from different organisations, the role assume is not working, our workaround was to create a user in the same organisation, then the assume works. But this is not our main use case.

shanemcd commented 2 years ago

I don't know of any way to do this given the fact that jobs run inside of a container and we do not have access to the underlying host. We'll leave this open in case there's some way we're not aware of or if a better solution comes along in the future.

liad5h commented 8 months ago

I authenticated to AWS via an IAM role by doing the following:

Under Instance Groups I configured the default Container Group with this configuration:

kind: Pod
metadata:
  namespace: awx
spec:
  serviceAccountName: <service_account_name>
  automountServiceAccountToken: false
  containers:
    - image: quay.io/ansible/awx-ee:latest
      name: worker
      args:
        - ansible-runner
        - worker
        - '--private-data-dir=/runner'
      resources:
        requests:
          cpu: 250m
          memory: 100Mi

I configured the service account to assume an IAM role as described in https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html

In an inventory source I configured the source variables:


compose:
  ansible_host: private_ip_address
  ec2_account_id: owner_id
  ec2_ami_launch_index: ami_launch_index | string
  ec2_architecture: architecture
  ec2_block_devices: dict(block_device_mappings | map(attribute='device_name') | list | zip(block_device_mappings | map(attribute='ebs.volume_id') | list))
  ec2_client_token: client_token
  ec2_dns_name: public_dns_name
  ec2_ebs_optimized: ebs_optimized
  ec2_eventsSet: events | default("")
  ec2_group_name: placement.group_name
  ec2_hypervisor: hypervisor
  ec2_id: instance_id
  ec2_image_id: image_id
  ec2_instance_profile: iam_instance_profile | default("")
  ec2_instance_type: instance_type
  ec2_ip_address: public_ip_address
  ec2_kernel: kernel_id | default("")
  ec2_key_name: key_name
  ec2_launch_time: launch_time | regex_replace(" ", "T") | regex_replace("(\+)(\d\d):(\d)(\d)$", ".\g<2>\g<3>Z")
  ec2_monitored: monitoring.state in ['enabled', 'pending']
  ec2_monitoring_state: monitoring.state
  ec2_persistent: persistent | default(false)
  ec2_placement: placement.availability_zone
  ec2_platform: platform | default("")
  ec2_private_dns_name: private_dns_name
  ec2_private_ip_address: private_ip_address
  ec2_public_dns_name: public_dns_name
  ec2_ramdisk: ramdisk_id | default("")
  ec2_reason: state_transition_reason
  ec2_region: placement.region
  ec2_requester_id: requester_id | default("")
  ec2_root_device_name: root_device_name
  ec2_root_device_type: root_device_type
  ec2_security_group_ids: security_groups | map(attribute='group_id') | list |  join(',')
  ec2_security_group_names: security_groups | map(attribute='group_name') | list |  join(',')
  ec2_sourceDestCheck: source_dest_check | default(false) | lower | string
  ec2_spot_instance_request_id: spot_instance_request_id | default("")
  ec2_state: state.name
  ec2_state_code: state.code
  ec2_state_reason: state_reason.message if state_reason is defined else ""
  ec2_subnet_id: subnet_id | default("")
  ec2_tag_Name: tags.Name
  ec2_virtualization_type: virtualization_type
  ec2_vpc_id: vpc_id | default("")
groups: {}
hostnames:
  - instance-id
  - tag:Name
filters:
  instance-state-name:
  - running
iam_role_arn: <role_arn>```