From d73e0426ba6116cad384bffd0af62326525bc514 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Mon, 15 Dec 2025 13:23:14 -0500 Subject: [PATCH 1/8] feat: WIP add eks_pod_identity_association and info modules Signed-off-by: Ali AlKhalidi --- .../modules/eks_pod_identity_association.py | 356 ++++++++++++++++++ .../eks_pod_identity_association_info.py | 157 ++++++++ .../eks_pod_identity_association/aliases | 2 + .../defaults/main.yml | 41 ++ .../files/eks-nodegroup-trust-policy.json | 12 + ...pod-identity-association-trust-policy.json | 16 + .../files/eks-trust-policy.json | 12 + .../tasks/cleanup.yml | 77 ++++ .../tasks/dependecies.yml | 168 +++++++++ .../tasks/full_test.yml | 7 + .../tasks/k8s_depedencies.yml | 16 + .../tasks/main.yml | 18 + ...ks-pod-identity-association-policy.json.j2 | 10 + 13 files changed, 892 insertions(+) create mode 100644 plugins/modules/eks_pod_identity_association.py create mode 100644 plugins/modules/eks_pod_identity_association_info.py create mode 100644 tests/integration/targets/eks_pod_identity_association/aliases create mode 100644 tests/integration/targets/eks_pod_identity_association/defaults/main.yml create mode 100644 tests/integration/targets/eks_pod_identity_association/files/eks-nodegroup-trust-policy.json create mode 100644 tests/integration/targets/eks_pod_identity_association/files/eks-pod-identity-association-trust-policy.json create mode 100644 tests/integration/targets/eks_pod_identity_association/files/eks-trust-policy.json create mode 100644 tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml create mode 100644 tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml create mode 100644 tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml create mode 100644 tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml create mode 100644 tests/integration/targets/eks_pod_identity_association/tasks/main.yml create mode 100644 tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 diff --git a/plugins/modules/eks_pod_identity_association.py b/plugins/modules/eks_pod_identity_association.py new file mode 100644 index 00000000000..84b0d80a47c --- /dev/null +++ b/plugins/modules/eks_pod_identity_association.py @@ -0,0 +1,356 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION = r""" +--- +module: eks_pod_identity_association +version_added: 10.0.0 +short_description: Manage an EKS pod identity association +description: + - Manage an AWS EKS pod identity association. See + U(https://docs.aws.amazon.com/eks/latest/userguide/pod-id-association.html) + U(https://docs.aws.amazon.com/eks/latest/userguide/pod-id-assign-target-role.html) for details. +author: + - "Ali Al-Khalidi (@doteast)" +options: + cluster_name: + description: Name of EKS Cluster. + required: true + type: str + role_arn: + description: ARN of IAM role to associate with the service account. + type: str + required: true + target_role_arn: + description: ARN of IAM target role to associate with the service account. + type: str + required: false + namespace: + description: + - EKS Kubernetes namespace inside the cluster to create the association in. + - Can be used only during creation. + type: str + required: true + service_account: + description: + - EKS Kubernetes service account inside the cluster to associate the IAM credentials with. + - Can be used only during creation. + type: str + required: true + tags: + description: + - A dictionary of resource tags. + - Can be used only during creation. + type: dict + aliases: ['resource_tags'] + disable_session_tags: + description: + - Whether or not to alter existing targets in the group to match what is passed with the module + required: false + default: false + type: bool + state: + description: + - Create or destroy the association. + required: false + default: present + choices: [ 'present', 'absent' ] + type: str +extends_documentation_fragment: + - amazon.aws.common.modules + - amazon.aws.region.modules + - amazon.aws.tags + - amazon.aws.boto3 +""" + +EXAMPLES = r""" +# Note: These examples do not set authentication details, see the AWS Guide for details. + +- name: Create pod identity association + community.aws.eks_pod_identity_association: + cluster_name: myeks + role_arn: arn:aws:iam:us-east-1:1231231123:role/abcd + namespace: test-ns + service_account: test-sa + state: present +""" + +RETURN = r""" +cluster_name: + description: The name of the cluster that the association is in. + returned: when state is present + type: str + sample: test_cluster +role_arn: + description: ARN of the IAM role to associate with the service account. + returned: when state is present + type: str + sample: arn:aws:iam:us-east-1:1231231123:role/abcd +target_role_arn: + description: ARN of the target IAM role to associate with the service account. + returned: when state is present + type: str + sample: arn:aws:iam:us-east-1:1231231123:role/abcd +namespace: + description: The name of the Kubernetes namespace inside the cluster to create the association in. + returned: when state present + type: str + sample: test-ns +service_account: + description: The name of the Kubernetes service account inside the cluster to associate the IAM credentials with. + returned: when state present + type: str + sample: test-sa +association_arn: + description: ARN of the association. + returned: when state present + type: str + sample: arn:aws:els:us-east-1:1231231123:association/abcd +association_id: + description: The ID of the association. + returned: when state present + type: str + sample: TBD +tags: + description: Metadata that assists with categorization and organization. + returned: when state present + type: dict + sample: + foo: bar +disable_session_tags: + description: The state of the automatic sessions tags. + returned: when state present + type: bool + sample: True +external_id: + description: The unique identifier for this EKS Pod Identity association for a target IAM role. + returned: when state present + type: str + sample: TBD +created_at: + description: Association creation date and time. + returned: when state is present + type: str + sample: '2022-01-18T20:00:00.111000+00:00' +modified_at: + description: Association modified date and time. + returned: when state is present + type: str + sample: '2022-01-18T20:00:00.111000+00:00' +owner_arn: + description: If defined, the EKS Pod Identity association is owned by an Amazon EKS add-on. + returned: when state present + type: str + sample: TBD +""" + +try: + import botocore +except ImportError: + pass # caught by AnsibleAWSModule +from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict + +from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule + +PARAMS_MAP = { + "cluster_name": "clusterName", + "role_arn": "roleArn", + "target_role_arn": "targetRoleArn", + "namespace": "namespace", + "service_account": "serviceAccount", + "disable_session_tags": "disableSessionTags", + "tags": "Tags", +} + +DEFAULTS = { + "disable_session_tags": False, +} + +CREATE_ONLY_PARAMS = [ + "namespace", + "service_account", + "tags", +] + +def _set_kwarg(kwargs, key, value): + mapped_key = PARAMS_MAP[key] + key_list = [mapped_key] + data = kwargs + data[key_list[0]] = value + + +def _fill_kwargs(module, apply_defaults=True, ignore_create_params=False): + kwargs = {} + if apply_defaults: + for p_name, p_value in DEFAULTS.items(): + _set_kwarg(kwargs, p_name, p_value) + for p_name in module.params: + if ignore_create_params and p_name in CREATE_ONLY_PARAMS: + # ignore CREATE_ONLY_PARAMS on update + continue + if p_name in PARAMS_MAP and module.params[p_name] is not None: + _set_kwarg(kwargs, p_name, module.params[p_name]) + else: + # ignore + pass + return kwargs + +def _needs_change(current, desired): + needs_change = False + for key in desired: + current_value = current[key] + desired_value = desired[key] + if current_value != desired_value: + needs_change = True + break + # + return needs_change + +def get_association_id(client, module): + cluster_name = module.params["cluster_name"] + namespace = module.params["namespace"] + service_account = module.params["service_account"] + association_id = None + try: + paginator = client.get_paginator("list_pod_identity_associations") + response = paginator.paginate(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account).build_full_result() + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't list pod identity associations.") + + if len(response["associations"]) > 1: + module.warn("found multiple associations matcing fields") + if len(response["associations"]) == 1: + association_id = response["associations"][0]["associationId"] + return association_id + + +def get_association_info(client, module, association_id, cluster_name): + try: + return client.describe_pod_identity_association( + clusterName=cluster_name, + associationId=association_id + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't get pod identity association details.") + + +def update_assocition(client, module, association_id): + kwargs = _fill_kwargs(module, apply_defaults=False, ignore_create_params=True) + cluster_name = module.params["cluster_name"] + kwargs["associationId"] = association_id + # get current state for comparison: + api_result = get_association_info(client, module, association_id, cluster_name) + association_arn = api_result["associationArn"] + result = { + "association_id": association_id, "association_arn": association_arn + } + changed = False + if _needs_change(api_result, kwargs): + changed = True + if not module.check_mode: + api_result = client.update_pod_identity_association(**kwargs) + result = camel_dict_to_snake_dict(api_result["association"], ignore_list=["Tags"]) + # + + return {"association": result, "changed": changed} + +def delete_association(client, module, association_id, cluster_name): + + try: + response = client.delete_pod_identity_association( + clusterName=cluster_name, + associationId=association_id + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't delete pod identity association.") + + return response + +def create_assocition(client, module): + kwargs = _fill_kwargs(module) + + changed = True + result = client.create_pod_identity_association(**kwargs) + + return {"association": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": changed} + + +def ensure_present(client, module): + if module.check_mode: + return { + "association": { + "association_arn": "fakeArn", + "association_id": "fakeId" + }, + "changed": True + } + + association_id = get_association_id(client, module) + if association_id: + return update_assocition(client, module, association_id) + + return create_assocition(client, module) + + +def ensure_absent(client, module): + cluster_name = module.params["cluster_name"] + result = {"cluster_name": cluster_name, "association_id": None} + if module.check_mode: + return {"association": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": True} + association_id = get_association_id(client, module) + result["association_id"] = association_id + + if not association_id: + # silently ignore delete of unknown association + return {"association": result, "changed": False} + + try: + api_result = get_association_info(client, module, association_id, cluster_name) + delete_association(client, module, association_id, cluster_name) + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e) + + return {"association": result, "changed": True} + +def main(): + argument_spec = dict( + cluster_name=dict(type="str", required=True), + role_arn=dict(type="str", required=True), + target_role_arn=dict(type="str"), + namespace=dict(type="str",required=True), + service_account=dict(type="str", required=True), + disable_session_tags=dict(type="bool", default=False), + target_role_arn=dict(type="str"), + tags=dict(type="dict"), + state=dict(choices=["absent", "present"], default="present"), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + try: + client = module.client("eks") + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: + module.fail_json_aws(e, msg="Couldn't connect to AWS.") + + if module.params.get("state") == "present": + try: + result = ensure_present(client, module) + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e) + else: + try: + result = ensure_absent(client, module) + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/eks_pod_identity_association_info.py b/plugins/modules/eks_pod_identity_association_info.py new file mode 100644 index 00000000000..a4cba96eeb3 --- /dev/null +++ b/plugins/modules/eks_pod_identity_association_info.py @@ -0,0 +1,157 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: Contributors to the Ansible project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION = r""" +--- +module: eks_pod_identity_association_info +version_added: 10.0.0 +short_description: Retrieve EKS pod identity association details +description: + - Get details about a pod identity association. +author: + - Ali Al-Khalidi (@doteast) +options: + cluster_name: + description: Name of EKS Cluster. + required: true + type: str + association_id: + description: + - Get details for pod identity assosciation with specified Id. + type: str + namespace: + description: + - Get details for pod identity assosciations with specified namespace. + - Ignore when association Id is provided. + - Must be coupled with service_account. + type: str + service_account: + description: + - Get details for pod identity assosciation with specified service account. + - Ignore when association Id is provided. + - Must be coupled with namespace. + type: str + +extends_documentation_fragment: + - amazon.aws.boto3 + - amazon.aws.common.modules + - amazon.aws.region.modules +""" + + +EXAMPLES = r""" +- name: get current pod identity association settings by id + community.aws.eks_pod_identity_association_info: + cluster_name: myeks + association_id: "aws-pod-identity-association-id" + register: association_info +- name: get current pod identity association settings by namespace + community.aws.eks_pod_identity_association_info: + cluster_name: myeks + namespace: test-ns + register: association_ns_info +- name: get current pod identity association settings by service account and namespace + community.aws.eks_pod_identity_association_info: + cluster_name: myeks + namespace: test-ns + service_account: test-sa + register: association_info +""" + +RETURN = r""" +broker: + description: API response of describe_pod_identity_association() converted to snake yaml. + type: dict + returned: success +""" + +try: + import botocore +except ImportError: + # handled by AnsibleAWSModule + pass + +from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict + +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule + + +def get_association_id(client, module): + cluster_name = module.params["cluster_name"] + namespace = module.params["namespace"] + service_account = module.params["service_account"] + association_id = None + try: + paginator = client.get_paginator("list_pod_identity_associations") + response = paginator.paginate(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account).build_full_result() + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't list pod identity associations.") + + if len(response["associations"]) > 1: + module.warn("found multiple associations matcing fields") + if len(response["associations"]) == 1: + association_id = response["associations"][0]["associationId"] + return association_id + + +def get_association_info(client, module, association_id, cluster_name): + try: + return client.describe_pod_identity_association( + clusterName=cluster_name, + associationId=association_id + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't get pod identity association details.") + + +def main(): + argument_spec = dict( + cluster_name=dict(type="str", required=True), + association_id=dict(type="str"), + namespace=dict(type="str"), + service_account=dict(type="str") + ) + required_one_of = ( + ( + "association_id", + "namespace", + ), + ) + required_together = ( + ( + "namespace", + "service_account", + ), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + required_one_of=required_one_of, + required_together=required_together, + supports_check_mode=True, + ) + cluster_name = module.params["cluster_name"] + association_id = module.params["association_id"] + + client = module.client("eks") + + try: + if not association_id: + association_id = get_association_id(client, module) + if not association_id: + if module.check_mode: + module.exit_json( + association={"association_id": "fakeId", "clusert_name": cluster_name if cluster_name else "fakeName"} + ) + result = get_association_info(client, module, association_id, cluster_name) + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e) + # + module.exit_json(association=camel_dict_to_snake_dict(result["association"], ignore_list=["Tags"])) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/eks_pod_identity_association/aliases b/tests/integration/targets/eks_pod_identity_association/aliases new file mode 100644 index 00000000000..4c06f2662f0 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/aliases @@ -0,0 +1,2 @@ +cloud/aws +time=60m diff --git a/tests/integration/targets/eks_pod_identity_association/defaults/main.yml b/tests/integration/targets/eks_pod_identity_association/defaults/main.yml new file mode 100644 index 00000000000..72b704d685d --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/defaults/main.yml @@ -0,0 +1,41 @@ +eks_cluster_name: "{{ resource_prefix }}" +eks_nodegroup_name_a: "ng-template-{{ resource_prefix }}-a" +s3_bucket_name: "pia-{{ resource_prefix }}" +k8s_namespace: "pia-{{ resource_prefix }}-ns" +k8s_service_account: "pia-{{ resource_prefix }}-sa" + + +eks_subnets: + - zone: a + cidr: 10.0.1.0/24 + type: private + - zone: b + cidr: 10.0.2.0/24 + type: public + +eks_nodegroup_ami_type: "AL2_x86_64" + +eks_security_groups: + - name: "{{ eks_cluster_name }}-control-plane-sg" + description: "EKS Control Plane Security Group" + rules: + - group_name: "{{ eks_cluster_name }}-workers-sg" + group_desc: "EKS Worker Security Group" + ports: 443 + proto: tcp + rules_egress: + - group_name: "{{ eks_cluster_name }}-workers-sg" + group_desc: "EKS Worker Security Group" + from_port: 1025 + to_port: 65535 + proto: tcp + - name: "{{ eks_cluster_name }}-workers-sg" + description: "EKS Worker Security Group" + rules: + - group_name: "{{ eks_cluster_name }}-workers-sg" + proto: tcp + from_port: 1 + to_port: 65535 + - group_name: "{{ eks_cluster_name }}-control-plane-sg" + ports: 10250 + proto: tcp \ No newline at end of file diff --git a/tests/integration/targets/eks_pod_identity_association/files/eks-nodegroup-trust-policy.json b/tests/integration/targets/eks_pod_identity_association/files/eks-nodegroup-trust-policy.json new file mode 100644 index 00000000000..fa43376a6e4 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/files/eks-nodegroup-trust-policy.json @@ -0,0 +1,12 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] +} diff --git a/tests/integration/targets/eks_pod_identity_association/files/eks-pod-identity-association-trust-policy.json b/tests/integration/targets/eks_pod_identity_association/files/eks-pod-identity-association-trust-policy.json new file mode 100644 index 00000000000..60dd799259e --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/files/eks-pod-identity-association-trust-policy.json @@ -0,0 +1,16 @@ +{ + "Version":"2012-10-17", + "Statement": [ + { + "Sid": "AllowEksAuthToAssumeRoleForPodIdentity", + "Effect": "Allow", + "Principal": { + "Service": "pods.eks.amazonaws.com" + }, + "Action": [ + "sts:AssumeRole", + "sts:TagSession" + ] + } + ] +} \ No newline at end of file diff --git a/tests/integration/targets/eks_pod_identity_association/files/eks-trust-policy.json b/tests/integration/targets/eks_pod_identity_association/files/eks-trust-policy.json new file mode 100644 index 00000000000..85cfb59dd28 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/files/eks-trust-policy.json @@ -0,0 +1,12 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] +} diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml new file mode 100644 index 00000000000..b3bf8c118a7 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml @@ -0,0 +1,77 @@ +- name: remove EKS cluster + eks_cluster: + name: '{{ eks_cluster_name }}' + state: absent + wait: true + register: eks_delete + ignore_errors: true +- name: create list of all additional EKS security groups + set_fact: + additional_eks_sg: + - name: '{{ eks_cluster_name }}-workers-sg' + +- name: set all security group rule lists to empty to remove circular dependency + ec2_security_group: + name: '{{ item.name }}' + description: '{{ item.description }}' + state: present + rules: [] + rules_egress: [] + purge_rules: true + purge_rules_egress: true + vpc_id: '{{ setup_vpc.vpc.id }}' + with_items: '{{ eks_security_groups }}' + ignore_errors: true + +- name: remove security groups + ec2_security_group: + name: '{{ item.name }}' + state: absent + vpc_id: '{{ setup_vpc.vpc.id }}' + with_items: '{{ eks_security_groups|reverse|list + additional_eks_sg }}' + ignore_errors: true + +- name: Delete securitygroup for node access + amazon.aws.ec2_security_group: + name: 'ansible-test-eks_nodegroup' + description: "SSH access" + vpc_id: '{{ setup_vpc.vpc.id }}' + rules: [] + state: absent + +- name: Delete Keypair for Access to Nodegroup nodes + amazon.aws.ec2_key: + name: "ansible-test-eks_nodegroup" + state: absent + +- name: remove Route Tables + ec2_vpc_route_table: + state: absent + vpc_id: '{{ setup_vpc.vpc.id }}' + route_table_id: '{{ item }}' + lookup: id + with_items: + - '{{ public_route_table.route_table.route_table_id }}' + ignore_errors: true + +- name: remove setup subnet + ec2_vpc_subnet: + az: '{{ aws_region }}{{ item.zone }}' + vpc_id: '{{ setup_vpc.vpc.id }}' + cidr: '{{ item.cidr}}' + state: absent + with_items: '{{ eks_subnets }}' + ignore_errors: true + +- name: remove Internet Gateway + amazon.aws.ec2_vpc_igw: + state: absent + vpc_id: '{{ setup_vpc.vpc.id}}' + ignore_errors: true + +- name: remove setup VPC + ec2_vpc_net: + cidr_block: 10.0.0.0/16 + state: absent + name: '{{ resource_prefix }}_aws_eks' + ignore_errors: true diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml new file mode 100644 index 00000000000..14c82edbe71 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml @@ -0,0 +1,168 @@ +# Create a EKS Cluster to test Nodegroup +# This space was a copy by aws_eks_cluster integration test +- name: ensure IAM instance role exists + iam_role: + name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster + assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}' + state: present + create_instance_profile: 'no' + managed_policies: + - AmazonEKSServicePolicy + - AmazonEKSClusterPolicy + register: iam_role + +- name: create a VPC to work in + ec2_vpc_net: + cidr_block: 10.0.0.0/16 + state: present + name: '{{ resource_prefix }}_aws_eks' + resource_tags: + Name: '{{ resource_prefix }}_aws_eks' + register: setup_vpc + +- name: create subnets + ec2_vpc_subnet: + az: '{{ aws_region }}{{ item.zone }}' + tags: '{ "Name": "{{ resource_prefix }}_aws_eks-subnet-{{ item.type }}-{{ item.zone }}" }' + vpc_id: '{{ setup_vpc.vpc.id }}' + cidr: '{{ item.cidr }}' + map_public: 'yes' + state: present + register: setup_subnets + with_items: + - '{{ eks_subnets }}' + +- name: create Internet Gateway + amazon.aws.ec2_vpc_igw: + vpc_id: '{{ setup_vpc.vpc.id }}' + state: present + tags: + Name: '{{ resource_prefix }}_IGW' + register: setup_igw + +- name: Set up public subnet route table + community.aws.ec2_vpc_route_table: + vpc_id: '{{ setup_vpc.vpc.id }}' + tags: + Name: "EKS-ng-{{ tiny_prefix }}" + subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' + routes: + - dest: 0.0.0.0/0 + gateway_id: '{{ setup_igw.gateway_id }}' + register: public_route_table + +- name: create security groups to use for EKS + ec2_security_group: + name: '{{ item.name }}' + description: '{{ item.description }}' + state: present + rules: '{{ item.rules }}' + rules_egress: '{{ item.rules_egress|default(omit) }}' + vpc_id: '{{ setup_vpc.vpc.id }}' + with_items: '{{ eks_security_groups }}' + register: setup_security_groups + +- name: create EKS cluster + eks_cluster: + name: '{{ eks_cluster_name }}' + security_groups: '{{ eks_security_groups | map(attribute=''name'') }}' + subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' + role_arn: '{{ iam_role.iam_role.arn }}' + version: 1.32 + wait: true + register: eks_create + +- name: check that EKS cluster was created + assert: + that: + - eks_create.name == eks_cluster_name + +# Dependecies to eks nodegroup +- name: create IAM instance role + iam_role: + name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng' + assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}' + state: present + create_instance_profile: no + managed_policies: + - AmazonEKSWorkerNodePolicy + - AmazonEC2ContainerRegistryReadOnly + - AmazonEKS_CNI_Policy + register: iam_role_eks_nodegroup + +- name: Pause a few seconds to ensure IAM role is available to next task + pause: + seconds: 10 + +- name: Create securitygroup for node access + amazon.aws.ec2_security_group: + name: 'ansible-test-eks_nodegroup' + description: "SSH access" + vpc_id: '{{ setup_vpc.vpc.id }}' + rules: + - proto: tcp + ports: + - 22 + cidr_ip: 0.0.0.0/0 + register: securitygroup_eks_nodegroup + +- name: Create Keypair for Access to Nodegroup nodes + amazon.aws.ec2_key: + name: "ansible-test-eks_nodegroup" + register: ec2_key_eks_nodegroup + +- name: create nodegroup (check mode) + eks_nodegroup: + name: '{{ eks_nodegroup_name_a }}' + state: present + cluster_name: '{{ eks_cluster_name }}' + node_role: '{{ iam_role_eks_nodegroup.iam_role.arn }}' + subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' + scaling_config: + min_size: 1 + max_size: 3 + desired_size: 2 + disk_size: 30 + instance_types: ['t3.small'] + ami_type: '{{ eks_nodegroup_ami_type }}' + update_config: + max_unavailable_percentage: 50 + labels: + 'env': 'test' + taints: + - key: 'env' + value: 'test' + effect: 'PREFER_NO_SCHEDULE' + capacity_type: 'SPOT' + tags: + 'foo': 'bar' + remote_access: + ec2_ssh_key: "{{ ec2_key_eks_nodegroup.key.name }}" + source_sg: + - "{{ securitygroup_eks_nodegroup.group_id }}" + wait: False + register: eks_nodegroup_result + check_mode: True + +- name: check that eks_nodegroup is created (check mode) + assert: + that: + - eks_nodegroup_result.changed + +- name: create IAM role for Pod Identity + iam_role: + name: 'ansible-test-{{ tiny_prefix }}-eks-pod-identity-association' + assume_role_policy_document: '{{ lookup(''file'',''eks-pod-identity-association-trust-policy.json'') }}' + state: present + create_instance_profile: no + managed_policies: [] + register: pod_identity_association_role + +- name: Create policy from file + amazon.aws.iam_policy: + iam_type: role + iam_name: "{{ pod_identity_association_role.role_name }}" + policy_name: 'ansible-test-{{ tiny_prefix }}-eks-pod-identity-association' + state: present + policy_json: "{{ lookup('template', 'eks-pod-identity-association-policy.json.j2') }}" + register: pod_identity_association_policy diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml b/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml new file mode 100644 index 00000000000..92e0838276f --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml @@ -0,0 +1,7 @@ +- name: Create pod identity association + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.role_name }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + state: present \ No newline at end of file diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml b/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml new file mode 100644 index 00000000000..c6db6028f49 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml @@ -0,0 +1,16 @@ +- name: Create a k8s namespace + kubernetes.core.k8s: + name: "{{ k8s_namespace }}" + api_version: v1 + kind: Namespace + state: present + +- name: Create a ServiceAccount object from an inline definition + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: "{{ k8s_service_account }}" + namespace: "{{ k8s_namespace }}" diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/main.yml b/tests/integration/targets/eks_pod_identity_association/tasks/main.yml new file mode 100644 index 00000000000..c91e356039c --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: 'eks_nodegroup integration tests' + collections: + - amazon.aws + - community.aws + - kubernetes.core + module_defaults: + group/aws: + access_key: '{{ aws_access_key }}' + secret_key: '{{ aws_secret_key }}' + session_token: '{{ security_token | default(omit) }}' + region: '{{ aws_region }}' + block: + - include_tasks: dependecies.yml +# - include_tasks: k8s_dependencies.yml +# - include_tasks: full_test.yml + # always: + # - include_tasks: cleanup.yml diff --git a/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 b/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 new file mode 100644 index 00000000000..da61438e4e7 --- /dev/null +++ b/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 @@ -0,0 +1,10 @@ +{ + "Version":"2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::{{ bucket_name }}" + } + ] +} \ No newline at end of file From a10d93060c97e4dd8a88d1d98316f67d90c580bb Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Tue, 16 Dec 2025 09:04:59 -0500 Subject: [PATCH 2/8] fix: remove duplicate param and simply association listing Signed-off-by: Ali AlKhalidi --- plugins/modules/eks_pod_identity_association.py | 6 ++---- plugins/modules/eks_pod_identity_association_info.py | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/modules/eks_pod_identity_association.py b/plugins/modules/eks_pod_identity_association.py index 84b0d80a47c..694016f1cc6 100644 --- a/plugins/modules/eks_pod_identity_association.py +++ b/plugins/modules/eks_pod_identity_association.py @@ -215,14 +215,13 @@ def get_association_id(client, module): service_account = module.params["service_account"] association_id = None try: - paginator = client.get_paginator("list_pod_identity_associations") - response = paginator.paginate(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account).build_full_result() + response = client.list_pod_identity_associations(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't list pod identity associations.") if len(response["associations"]) > 1: module.warn("found multiple associations matcing fields") - if len(response["associations"]) == 1: + if len(response["associations"]) >= 1: association_id = response["associations"][0]["associationId"] return association_id @@ -323,7 +322,6 @@ def main(): namespace=dict(type="str",required=True), service_account=dict(type="str", required=True), disable_session_tags=dict(type="bool", default=False), - target_role_arn=dict(type="str"), tags=dict(type="dict"), state=dict(choices=["absent", "present"], default="present"), ) diff --git a/plugins/modules/eks_pod_identity_association_info.py b/plugins/modules/eks_pod_identity_association_info.py index a4cba96eeb3..b67997097bc 100644 --- a/plugins/modules/eks_pod_identity_association_info.py +++ b/plugins/modules/eks_pod_identity_association_info.py @@ -85,18 +85,18 @@ def get_association_id(client, module): service_account = module.params["service_account"] association_id = None try: - paginator = client.get_paginator("list_pod_identity_associations") - response = paginator.paginate(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account).build_full_result() + response = client.list_pod_identity_associations(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't list pod identity associations.") if len(response["associations"]) > 1: module.warn("found multiple associations matcing fields") - if len(response["associations"]) == 1: + if len(response["associations"]) >= 1: association_id = response["associations"][0]["associationId"] return association_id + def get_association_info(client, module, association_id, cluster_name): try: return client.describe_pod_identity_association( From 735ddba6c299cc323515abdc7ddfe1d5eb188151 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Tue, 16 Dec 2025 09:18:44 -0500 Subject: [PATCH 3/8] chore: add module namespaces, fix role policy template, and add missing kubeconfig file task Signed-off-by: Ali AlKhalidi --- .../tasks/cleanup.yml | 12 +++++------ .../tasks/dependecies.yml | 20 +++++++++++-------- ...ks-pod-identity-association-policy.json.j2 | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml index b3bf8c118a7..e9ae96be6a7 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml @@ -1,5 +1,5 @@ - name: remove EKS cluster - eks_cluster: + community.aws.eks_cluster: name: '{{ eks_cluster_name }}' state: absent wait: true @@ -11,7 +11,7 @@ - name: '{{ eks_cluster_name }}-workers-sg' - name: set all security group rule lists to empty to remove circular dependency - ec2_security_group: + amazon.aws.ec2_security_group: name: '{{ item.name }}' description: '{{ item.description }}' state: present @@ -24,7 +24,7 @@ ignore_errors: true - name: remove security groups - ec2_security_group: + amazon.aws.ec2_security_group: name: '{{ item.name }}' state: absent vpc_id: '{{ setup_vpc.vpc.id }}' @@ -45,7 +45,7 @@ state: absent - name: remove Route Tables - ec2_vpc_route_table: + amazon.aws.ec2_vpc_route_table: state: absent vpc_id: '{{ setup_vpc.vpc.id }}' route_table_id: '{{ item }}' @@ -55,7 +55,7 @@ ignore_errors: true - name: remove setup subnet - ec2_vpc_subnet: + amazon.aws.ec2_vpc_subnet: az: '{{ aws_region }}{{ item.zone }}' vpc_id: '{{ setup_vpc.vpc.id }}' cidr: '{{ item.cidr}}' @@ -70,7 +70,7 @@ ignore_errors: true - name: remove setup VPC - ec2_vpc_net: + amazon.aws.ec2_vpc_net: cidr_block: 10.0.0.0/16 state: absent name: '{{ resource_prefix }}_aws_eks' diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml index 14c82edbe71..3b79ca3df15 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml @@ -1,7 +1,7 @@ # Create a EKS Cluster to test Nodegroup # This space was a copy by aws_eks_cluster integration test - name: ensure IAM instance role exists - iam_role: + amazon.aws.iam_role: name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}' state: present @@ -12,7 +12,7 @@ register: iam_role - name: create a VPC to work in - ec2_vpc_net: + amazon.aws.ec2_vpc_net: cidr_block: 10.0.0.0/16 state: present name: '{{ resource_prefix }}_aws_eks' @@ -21,7 +21,7 @@ register: setup_vpc - name: create subnets - ec2_vpc_subnet: + amazon.aws.ec2_vpc_subnet: az: '{{ aws_region }}{{ item.zone }}' tags: '{ "Name": "{{ resource_prefix }}_aws_eks-subnet-{{ item.type }}-{{ item.zone }}" }' vpc_id: '{{ setup_vpc.vpc.id }}' @@ -52,7 +52,7 @@ register: public_route_table - name: create security groups to use for EKS - ec2_security_group: + amazon.aws.ec2_security_group: name: '{{ item.name }}' description: '{{ item.description }}' state: present @@ -63,7 +63,7 @@ register: setup_security_groups - name: create EKS cluster - eks_cluster: + community.aws.eks_cluster: name: '{{ eks_cluster_name }}' security_groups: '{{ eks_security_groups | map(attribute=''name'') }}' subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' @@ -79,7 +79,7 @@ # Dependecies to eks nodegroup - name: create IAM instance role - iam_role: + amazon.aws.iam_role: name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng' assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}' state: present @@ -112,7 +112,7 @@ register: ec2_key_eks_nodegroup - name: create nodegroup (check mode) - eks_nodegroup: + community.aws.eks_nodegroup: name: '{{ eks_nodegroup_name_a }}' state: present cluster_name: '{{ eks_cluster_name }}' @@ -150,7 +150,7 @@ - eks_nodegroup_result.changed - name: create IAM role for Pod Identity - iam_role: + amazon.aws.iam_role: name: 'ansible-test-{{ tiny_prefix }}-eks-pod-identity-association' assume_role_policy_document: '{{ lookup(''file'',''eks-pod-identity-association-trust-policy.json'') }}' state: present @@ -166,3 +166,7 @@ state: present policy_json: "{{ lookup('template', 'eks-pod-identity-association-policy.json.j2') }}" register: pod_identity_association_policy + +- name: Create Kubeconfig cluster file + command: > + aws eks update-kubeconfig --region {{ region }} --name {{ eks_cluster_name }} \ No newline at end of file diff --git a/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 b/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 index da61438e4e7..0c9dabfff98 100644 --- a/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 +++ b/tests/integration/targets/eks_pod_identity_association/templates/eks-pod-identity-association-policy.json.j2 @@ -4,7 +4,7 @@ { "Effect": "Allow", "Action": "s3:GetObject", - "Resource": "arn:aws:s3:::{{ bucket_name }}" + "Resource": "arn:aws:s3:::{{ s3_bucket_name }}" } ] } \ No newline at end of file From 04f283b426a562b291cdf996a5319a0010d56292 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Tue, 16 Dec 2025 15:32:23 -0500 Subject: [PATCH 4/8] chore: more tests and fixes Signed-off-by: Ali AlKhalidi --- meta/runtime.yml | 2 + .../modules/eks_pod_identity_association.py | 43 ++- .../eks_pod_identity_association_info.py | 14 +- .../defaults/main.yml | 2 +- .../tasks/full_test.yml | 325 +++++++++++++++++- .../tasks/main.yml | 12 +- 6 files changed, 362 insertions(+), 36 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index 15743d53e91..72cdde706d3 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -119,6 +119,8 @@ action_groups: - eks_cluster - eks_fargate_profile - eks_nodegroup + - eks_pod_identity_association + - eks_pod_identity_association_info - elasticache - elasticache_info - elasticache_parameter_group diff --git a/plugins/modules/eks_pod_identity_association.py b/plugins/modules/eks_pod_identity_association.py index 694016f1cc6..1b03f18c04d 100644 --- a/plugins/modules/eks_pod_identity_association.py +++ b/plugins/modules/eks_pod_identity_association.py @@ -7,14 +7,14 @@ DOCUMENTATION = r""" --- module: eks_pod_identity_association -version_added: 10.0.0 +version_added: 10.1.0 short_description: Manage an EKS pod identity association description: - Manage an AWS EKS pod identity association. See U(https://docs.aws.amazon.com/eks/latest/userguide/pod-id-association.html) U(https://docs.aws.amazon.com/eks/latest/userguide/pod-id-assign-target-role.html) for details. author: - - "Ali Al-Khalidi (@doteast)" + - "Ali AlKhalidi (@doteast)" options: cluster_name: description: Name of EKS Cluster. @@ -46,12 +46,6 @@ - Can be used only during creation. type: dict aliases: ['resource_tags'] - disable_session_tags: - description: - - Whether or not to alter existing targets in the group to match what is passed with the module - required: false - default: false - type: bool state: description: - Create or destroy the association. @@ -61,7 +55,6 @@ type: str extends_documentation_fragment: - amazon.aws.common.modules - - amazon.aws.region.modules - amazon.aws.tags - amazon.aws.boto3 """ @@ -120,11 +113,6 @@ type: dict sample: foo: bar -disable_session_tags: - description: The state of the automatic sessions tags. - returned: when state present - type: bool - sample: True external_id: description: The unique identifier for this EKS Pod Identity association for a target IAM role. returned: when state present @@ -161,12 +149,10 @@ "target_role_arn": "targetRoleArn", "namespace": "namespace", "service_account": "serviceAccount", - "disable_session_tags": "disableSessionTags", "tags": "Tags", } DEFAULTS = { - "disable_session_tags": False, } CREATE_ONLY_PARAMS = [ @@ -216,6 +202,8 @@ def get_association_id(client, module): association_id = None try: response = client.list_pod_identity_associations(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't list pod identity associations.") @@ -232,6 +220,8 @@ def get_association_info(client, module, association_id, cluster_name): clusterName=cluster_name, associationId=association_id ) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't get pod identity association details.") @@ -250,7 +240,12 @@ def update_assocition(client, module, association_id): if _needs_change(api_result, kwargs): changed = True if not module.check_mode: - api_result = client.update_pod_identity_association(**kwargs) + try: + api_result = client.update_pod_identity_association(**kwargs) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't update pod identity association.") result = camel_dict_to_snake_dict(api_result["association"], ignore_list=["Tags"]) # @@ -263,6 +258,8 @@ def delete_association(client, module, association_id, cluster_name): clusterName=cluster_name, associationId=association_id ) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't delete pod identity association.") @@ -272,7 +269,16 @@ def create_assocition(client, module): kwargs = _fill_kwargs(module) changed = True - result = client.create_pod_identity_association(**kwargs) + try: + result = client.create_pod_identity_association(**kwargs) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") + except ( + botocore.exceptions.BotoCoreError, + botocore.exceptions.ClientError, + ) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg=f"Couldn't create association") + return {"association": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": changed} @@ -321,7 +327,6 @@ def main(): target_role_arn=dict(type="str"), namespace=dict(type="str",required=True), service_account=dict(type="str", required=True), - disable_session_tags=dict(type="bool", default=False), tags=dict(type="dict"), state=dict(choices=["absent", "present"], default="present"), ) diff --git a/plugins/modules/eks_pod_identity_association_info.py b/plugins/modules/eks_pod_identity_association_info.py index b67997097bc..feb7595c9a1 100644 --- a/plugins/modules/eks_pod_identity_association_info.py +++ b/plugins/modules/eks_pod_identity_association_info.py @@ -7,12 +7,12 @@ DOCUMENTATION = r""" --- module: eks_pod_identity_association_info -version_added: 10.0.0 +version_added: 10.1.0 short_description: Retrieve EKS pod identity association details description: - Get details about a pod identity association. author: - - Ali Al-Khalidi (@doteast) + - Ali AlKhalidi (@doteast) options: cluster_name: description: Name of EKS Cluster. @@ -38,7 +38,6 @@ extends_documentation_fragment: - amazon.aws.boto3 - amazon.aws.common.modules - - amazon.aws.region.modules """ @@ -48,11 +47,6 @@ cluster_name: myeks association_id: "aws-pod-identity-association-id" register: association_info -- name: get current pod identity association settings by namespace - community.aws.eks_pod_identity_association_info: - cluster_name: myeks - namespace: test-ns - register: association_ns_info - name: get current pod identity association settings by service account and namespace community.aws.eks_pod_identity_association_info: cluster_name: myeks @@ -86,6 +80,8 @@ def get_association_id(client, module): association_id = None try: response = client.list_pod_identity_associations(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't list pod identity associations.") @@ -103,6 +99,8 @@ def get_association_info(client, module, association_id, cluster_name): clusterName=cluster_name, associationId=association_id ) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't get pod identity association details.") diff --git a/tests/integration/targets/eks_pod_identity_association/defaults/main.yml b/tests/integration/targets/eks_pod_identity_association/defaults/main.yml index 72b704d685d..f5cff55b064 100644 --- a/tests/integration/targets/eks_pod_identity_association/defaults/main.yml +++ b/tests/integration/targets/eks_pod_identity_association/defaults/main.yml @@ -38,4 +38,4 @@ eks_security_groups: to_port: 65535 - group_name: "{{ eks_cluster_name }}-control-plane-sg" ports: 10250 - proto: tcp \ No newline at end of file + proto: tcp diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml b/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml index 92e0838276f..daca163c9c6 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml @@ -1,7 +1,328 @@ +#### +# Create +- name: Create pod identity association (check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association is created (check mode) + assert: + that: + - pod_identity_result.changed + + - name: Create pod identity association community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.role_name }}" + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association is created + assert: + that: + - pod_identity_result.changed + +- name: Create pod identity association (idempotency)(check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association is not changed (idempotency)(check mode) + assert: + that: + - not pod_identity_result.changed + + +- name: Create pod identity association (idempotency) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association is not changed (idempotency) + assert: + that: + - not pod_identity_result.changed + +- name: Get pod identity association info + community.aws.eks_pod_identity_association_info: + cluster_name: '{{ eks_cluster_name }}' + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + register: pod_identity_result_i1 + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association_info succeeds and returns same results + assert: + that: + - pod_identity_result_i1.changed + - pod_identity_result_i1.association_id == pod_identity_result.association_id + +### +# Update ignored + +- name: Test - attempt to update association with ignored parameter (tags) (check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'bar': 'foo' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association did nothing (check mode) + assert: + that: + - not pod_identity_result.changed + +- name: Test - attempt to update association with ignored parameter (tags) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'bar': 'foo' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association did nothing + assert: + that: + - not pod_identity_result.changed + +### +# Update + +- name: Test - attempt to update association with parameter (taregt_role_arn) (check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association is updated (check mode) + assert: + that: + - pod_identity_result.changed + +- name: Test - attempt to update association with parameter (taregt_role_arn) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association is updated + assert: + that: + - pod_identity_result.changed + +- name: Test - attempt to update association with parameter (taregt_role_arn) (check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association did nothing (check mode) + assert: + that: + - not pod_identity_result.changed + +- name: Test - attempt to update association with parameter (taregt_role_arn) (idempotency) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: present + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association did nothing + assert: + that: + - not pod_identity_result.changed + +### +# Delete + +- name: Delete association (check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: absent + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association is deleted (check mode) + assert: + that: + - pod_identity_result.changed + +- name: Delete association + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: absent + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association is deleted + assert: + that: + - pod_identity_result.changed + +- name: Delete association (idempotency)(check mode) + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + tags: + 'foo': 'bar' + state: absent + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + check_mode: True + +- name: check that eks_pod_identity_association is not changed (check mode) + assert: + that: + - not pod_identity_result.changed + +- name: Delete association + community.aws.eks_pod_identity_association: + cluster_name: '{{ eks_cluster_name }}' + role_arn: "{{ pod_identity_association_role.arn }}" + taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" - state: present \ No newline at end of file + tags: + 'foo': 'bar' + state: absent + register: pod_identity_result + variables: + account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" + environment: + AWS_DEFAULT_REGION: 'us-east-1' + +- name: check that eks_pod_identity_association is not changed + assert: + that: + - not pod_identity_result.changed diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/main.yml b/tests/integration/targets/eks_pod_identity_association/tasks/main.yml index c91e356039c..ac9a5b86afe 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/main.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/main.yml @@ -1,5 +1,5 @@ --- -- name: 'eks_nodegroup integration tests' +- name: 'eks_pod_identity_association and eks_pod_identity_association_info integration tests' collections: - amazon.aws - community.aws @@ -9,10 +9,10 @@ access_key: '{{ aws_access_key }}' secret_key: '{{ aws_secret_key }}' session_token: '{{ security_token | default(omit) }}' - region: '{{ aws_region }}' + region: "{{ aws_region | default('us-east-1') }}" block: - include_tasks: dependecies.yml -# - include_tasks: k8s_dependencies.yml -# - include_tasks: full_test.yml - # always: - # - include_tasks: cleanup.yml + - include_tasks: k8s_dependencies.yml + - include_tasks: full_test.yml + always: + - include_tasks: cleanup.yml From dfabf0f4dbcdec2f0274c0cf1dbcf77e85c55f00 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Wed, 17 Dec 2025 15:53:34 -0500 Subject: [PATCH 5/8] chore: passing tests Signed-off-by: Ali AlKhalidi --- .../modules/eks_pod_identity_association.py | 87 ++--- .../eks_pod_identity_association_info.py | 24 +- tests/integration/requirements.txt | 3 + tests/integration/requirements.yml | 1 + .../defaults/main.yml | 1 - .../tasks/cleanup.yml | 36 ++ .../tasks/dependecies.yml | 322 ++++++++++-------- .../tasks/full_test.yml | 186 +++++----- .../tasks/k8s_depedencies.yml | 8 + .../tasks/main.yml | 4 +- 10 files changed, 365 insertions(+), 307 deletions(-) diff --git a/plugins/modules/eks_pod_identity_association.py b/plugins/modules/eks_pod_identity_association.py index 1b03f18c04d..643ade62dd3 100644 --- a/plugins/modules/eks_pod_identity_association.py +++ b/plugins/modules/eks_pod_identity_association.py @@ -146,14 +146,12 @@ PARAMS_MAP = { "cluster_name": "clusterName", "role_arn": "roleArn", - "target_role_arn": "targetRoleArn", "namespace": "namespace", "service_account": "serviceAccount", - "tags": "Tags", + "tags": "tags", } -DEFAULTS = { -} +DEFAULTS = {} CREATE_ONLY_PARAMS = [ "namespace", @@ -161,6 +159,7 @@ "tags", ] + def _set_kwarg(kwargs, key, value): mapped_key = PARAMS_MAP[key] key_list = [mapped_key] @@ -184,6 +183,7 @@ def _fill_kwargs(module, apply_defaults=True, ignore_create_params=False): pass return kwargs + def _needs_change(current, desired): needs_change = False for key in desired: @@ -195,13 +195,16 @@ def _needs_change(current, desired): # return needs_change + def get_association_id(client, module): cluster_name = module.params["cluster_name"] namespace = module.params["namespace"] service_account = module.params["service_account"] association_id = None try: - response = client.list_pod_identity_associations(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account) + response = client.list_pod_identity_associations( + clusterName=cluster_name, namespace=namespace, serviceAccount=service_account + ) except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: @@ -216,10 +219,7 @@ def get_association_id(client, module): def get_association_info(client, module, association_id, cluster_name): try: - return client.describe_pod_identity_association( - clusterName=cluster_name, - associationId=association_id - ) + return client.describe_pod_identity_association(clusterName=cluster_name, associationId=association_id) except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: @@ -232,12 +232,9 @@ def update_assocition(client, module, association_id): kwargs["associationId"] = association_id # get current state for comparison: api_result = get_association_info(client, module, association_id, cluster_name) - association_arn = api_result["associationArn"] - result = { - "association_id": association_id, "association_arn": association_arn - } + result = camel_dict_to_snake_dict(api_result["association"], ignore_list=["Tags"]) changed = False - if _needs_change(api_result, kwargs): + if _needs_change(api_result["association"], kwargs): changed = True if not module.check_mode: try: @@ -251,13 +248,10 @@ def update_assocition(client, module, association_id): return {"association": result, "changed": changed} -def delete_association(client, module, association_id, cluster_name): +def delete_association(client, module, association_id, cluster_name): try: - response = client.delete_pod_identity_association( - clusterName=cluster_name, - associationId=association_id - ) + response = client.delete_pod_identity_association(clusterName=cluster_name, associationId=association_id) except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: @@ -265,34 +259,27 @@ def delete_association(client, module, association_id, cluster_name): return response + def create_assocition(client, module): kwargs = _fill_kwargs(module) changed = True - try: - result = client.create_pod_identity_association(**kwargs) - except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except - module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") - except ( - botocore.exceptions.BotoCoreError, - botocore.exceptions.ClientError, - ) as e: # pylint: disable=duplicate-except - module.fail_json_aws(e, msg=f"Couldn't create association") - + result = {"association_arn": "fakeArn", "association_id": "fakeId"} + if not module.check_mode: + try: + result = client.create_pod_identity_association(**kwargs) + except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except + module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") + except ( + botocore.exceptions.BotoCoreError, + botocore.exceptions.ClientError, + ) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg=f"Couldn't create association") return {"association": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": changed} def ensure_present(client, module): - if module.check_mode: - return { - "association": { - "association_arn": "fakeArn", - "association_id": "fakeId" - }, - "changed": True - } - association_id = get_association_id(client, module) if association_id: return update_assocition(client, module, association_id) @@ -302,30 +289,30 @@ def ensure_present(client, module): def ensure_absent(client, module): cluster_name = module.params["cluster_name"] - result = {"cluster_name": cluster_name, "association_id": None} - if module.check_mode: - return {"association": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": True} + changed = False + result = {"cluster_name": cluster_name, "association_id": "fakeId"} association_id = get_association_id(client, module) - result["association_id"] = association_id + result["association_id"] = association_id if association_id else "fakeId" if not association_id: # silently ignore delete of unknown association - return {"association": result, "changed": False} + return {"association": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": changed} - try: - api_result = get_association_info(client, module, association_id, cluster_name) - delete_association(client, module, association_id, cluster_name) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) + if not module.check_mode: + try: + result = delete_association(client, module, association_id, cluster_name) + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e) return {"association": result, "changed": True} + def main(): argument_spec = dict( cluster_name=dict(type="str", required=True), role_arn=dict(type="str", required=True), target_role_arn=dict(type="str"), - namespace=dict(type="str",required=True), + namespace=dict(type="str", required=True), service_account=dict(type="str", required=True), tags=dict(type="dict"), state=dict(choices=["absent", "present"], default="present"), @@ -352,7 +339,7 @@ def main(): except botocore.exceptions.ClientError as e: module.fail_json_aws(e) - module.exit_json(**result) + module.exit_json(**result) if __name__ == "__main__": diff --git a/plugins/modules/eks_pod_identity_association_info.py b/plugins/modules/eks_pod_identity_association_info.py index feb7595c9a1..9579f7aa7a3 100644 --- a/plugins/modules/eks_pod_identity_association_info.py +++ b/plugins/modules/eks_pod_identity_association_info.py @@ -79,7 +79,9 @@ def get_association_id(client, module): service_account = module.params["service_account"] association_id = None try: - response = client.list_pod_identity_associations(clusterName=cluster_name, namespace=namespace, serviceAccount=service_account) + response = client.list_pod_identity_associations( + clusterName=cluster_name, namespace=namespace, serviceAccount=service_account + ) except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: @@ -92,13 +94,9 @@ def get_association_id(client, module): return association_id - def get_association_info(client, module, association_id, cluster_name): try: - return client.describe_pod_identity_association( - clusterName=cluster_name, - associationId=association_id - ) + return client.describe_pod_identity_association(clusterName=cluster_name, associationId=association_id) except botocore.exceptions.EndpointConnectionError: # pylint: disable=duplicate-except module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS") except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: @@ -110,7 +108,7 @@ def main(): cluster_name=dict(type="str", required=True), association_id=dict(type="str"), namespace=dict(type="str"), - service_account=dict(type="str") + service_account=dict(type="str"), ) required_one_of = ( ( @@ -127,7 +125,7 @@ def main(): module = AnsibleAWSModule( argument_spec=argument_spec, - required_one_of=required_one_of, + mutually_exclusive=required_one_of, required_together=required_together, supports_check_mode=True, ) @@ -135,20 +133,24 @@ def main(): association_id = module.params["association_id"] client = module.client("eks") - + changed = False try: if not association_id: association_id = get_association_id(client, module) if not association_id: if module.check_mode: module.exit_json( - association={"association_id": "fakeId", "clusert_name": cluster_name if cluster_name else "fakeName"} + association={ + "association_id": "fakeId", + "clusert_name": cluster_name if cluster_name else "fakeName", + }, + changed=changed, ) result = get_association_info(client, module, association_id, cluster_name) except botocore.exceptions.ClientError as e: module.fail_json_aws(e) # - module.exit_json(association=camel_dict_to_snake_dict(result["association"], ignore_list=["Tags"])) + module.exit_json(association=camel_dict_to_snake_dict(result["association"], ignore_list=["Tags"]), changed=changed) if __name__ == "__main__": diff --git a/tests/integration/requirements.txt b/tests/integration/requirements.txt index aa71c96813e..9c40f069634 100644 --- a/tests/integration/requirements.txt +++ b/tests/integration/requirements.txt @@ -2,6 +2,9 @@ boto3 botocore +# Needed for EKS related tests +kubernetes + # netaddr is needed for ansible.utils.ipv6 netaddr virtualenv diff --git a/tests/integration/requirements.yml b/tests/integration/requirements.yml index d3e5b30321f..3b1fa1b4050 100644 --- a/tests/integration/requirements.yml +++ b/tests/integration/requirements.yml @@ -6,3 +6,4 @@ collections: - ansible.windows - community.crypto - community.general + - kubernetes.core diff --git a/tests/integration/targets/eks_pod_identity_association/defaults/main.yml b/tests/integration/targets/eks_pod_identity_association/defaults/main.yml index f5cff55b064..ef47754f45d 100644 --- a/tests/integration/targets/eks_pod_identity_association/defaults/main.yml +++ b/tests/integration/targets/eks_pod_identity_association/defaults/main.yml @@ -4,7 +4,6 @@ s3_bucket_name: "pia-{{ resource_prefix }}" k8s_namespace: "pia-{{ resource_prefix }}-ns" k8s_service_account: "pia-{{ resource_prefix }}-sa" - eks_subnets: - zone: a cidr: 10.0.1.0/24 diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml index e9ae96be6a7..11cae1751c3 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml @@ -1,3 +1,39 @@ +- name: delete policy + amazon.aws.iam_policy: + iam_type: role + iam_name: "{{ pod_identity_association_role.iam_role.role_name }}" + policy_name: 'ansible-test-{{ tiny_prefix }}-eks-pod-identity-association' + state: absent + policy_json: "{{ lookup('template', 'eks-pod-identity-association-policy.json.j2') }}" + ignore_errors: true + +- name: delete IAM role for Pod Identity + amazon.aws.iam_role: + name: 'ansible-test-{{ tiny_prefix }}-eks-pod-identity-association' + assume_role_policy_document: '{{ lookup(''file'',''eks-pod-identity-association-trust-policy.json'') }}' + state: absent + create_instance_profile: no + managed_policies: [] + ignore_errors: true + +- name: delete policy for replacement role + amazon.aws.iam_policy: + iam_type: role + iam_name: "{{ pod_identity_association_role_replacement.iam_role.role_name }}" + policy_name: 'ansible-test-{{ tiny_prefix }}-epia-replacement' + state: absent + policy_json: "{{ lookup('template', 'eks-pod-identity-association-policy.json.j2') }}" + ignore_errors: true + +- name: delete replacement IAM role for Pod Identity + amazon.aws.iam_role: + name: 'ansible-test-{{ tiny_prefix }}-epia-replacement' + assume_role_policy_document: '{{ lookup(''file'',''eks-pod-identity-association-trust-policy.json'') }}' + state: absent + create_instance_profile: no + managed_policies: [] + ignore_errors: true + - name: remove EKS cluster community.aws.eks_cluster: name: '{{ eks_cluster_name }}' diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml index 3b79ca3df15..2d472a123f7 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml @@ -1,153 +1,153 @@ # Create a EKS Cluster to test Nodegroup # This space was a copy by aws_eks_cluster integration test -- name: ensure IAM instance role exists - amazon.aws.iam_role: - name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster - assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}' - state: present - create_instance_profile: 'no' - managed_policies: - - AmazonEKSServicePolicy - - AmazonEKSClusterPolicy - register: iam_role - -- name: create a VPC to work in - amazon.aws.ec2_vpc_net: - cidr_block: 10.0.0.0/16 - state: present - name: '{{ resource_prefix }}_aws_eks' - resource_tags: - Name: '{{ resource_prefix }}_aws_eks' - register: setup_vpc - -- name: create subnets - amazon.aws.ec2_vpc_subnet: - az: '{{ aws_region }}{{ item.zone }}' - tags: '{ "Name": "{{ resource_prefix }}_aws_eks-subnet-{{ item.type }}-{{ item.zone }}" }' - vpc_id: '{{ setup_vpc.vpc.id }}' - cidr: '{{ item.cidr }}' - map_public: 'yes' - state: present - register: setup_subnets - with_items: - - '{{ eks_subnets }}' - -- name: create Internet Gateway - amazon.aws.ec2_vpc_igw: - vpc_id: '{{ setup_vpc.vpc.id }}' - state: present - tags: - Name: '{{ resource_prefix }}_IGW' - register: setup_igw - -- name: Set up public subnet route table - community.aws.ec2_vpc_route_table: - vpc_id: '{{ setup_vpc.vpc.id }}' - tags: - Name: "EKS-ng-{{ tiny_prefix }}" - subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' - routes: - - dest: 0.0.0.0/0 - gateway_id: '{{ setup_igw.gateway_id }}' - register: public_route_table - -- name: create security groups to use for EKS - amazon.aws.ec2_security_group: - name: '{{ item.name }}' - description: '{{ item.description }}' - state: present - rules: '{{ item.rules }}' - rules_egress: '{{ item.rules_egress|default(omit) }}' - vpc_id: '{{ setup_vpc.vpc.id }}' - with_items: '{{ eks_security_groups }}' - register: setup_security_groups - -- name: create EKS cluster - community.aws.eks_cluster: - name: '{{ eks_cluster_name }}' - security_groups: '{{ eks_security_groups | map(attribute=''name'') }}' - subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' - role_arn: '{{ iam_role.iam_role.arn }}' - version: 1.32 - wait: true - register: eks_create - -- name: check that EKS cluster was created - assert: - that: - - eks_create.name == eks_cluster_name - -# Dependecies to eks nodegroup -- name: create IAM instance role - amazon.aws.iam_role: - name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng' - assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}' - state: present - create_instance_profile: no - managed_policies: - - AmazonEKSWorkerNodePolicy - - AmazonEC2ContainerRegistryReadOnly - - AmazonEKS_CNI_Policy - register: iam_role_eks_nodegroup - -- name: Pause a few seconds to ensure IAM role is available to next task - pause: - seconds: 10 - -- name: Create securitygroup for node access - amazon.aws.ec2_security_group: - name: 'ansible-test-eks_nodegroup' - description: "SSH access" - vpc_id: '{{ setup_vpc.vpc.id }}' - rules: - - proto: tcp - ports: - - 22 - cidr_ip: 0.0.0.0/0 - register: securitygroup_eks_nodegroup - -- name: Create Keypair for Access to Nodegroup nodes - amazon.aws.ec2_key: - name: "ansible-test-eks_nodegroup" - register: ec2_key_eks_nodegroup - -- name: create nodegroup (check mode) - community.aws.eks_nodegroup: - name: '{{ eks_nodegroup_name_a }}' - state: present - cluster_name: '{{ eks_cluster_name }}' - node_role: '{{ iam_role_eks_nodegroup.iam_role.arn }}' - subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' - scaling_config: - min_size: 1 - max_size: 3 - desired_size: 2 - disk_size: 30 - instance_types: ['t3.small'] - ami_type: '{{ eks_nodegroup_ami_type }}' - update_config: - max_unavailable_percentage: 50 - labels: - 'env': 'test' - taints: - - key: 'env' - value: 'test' - effect: 'PREFER_NO_SCHEDULE' - capacity_type: 'SPOT' - tags: - 'foo': 'bar' - remote_access: - ec2_ssh_key: "{{ ec2_key_eks_nodegroup.key.name }}" - source_sg: - - "{{ securitygroup_eks_nodegroup.group_id }}" - wait: False - register: eks_nodegroup_result - check_mode: True - -- name: check that eks_nodegroup is created (check mode) - assert: - that: - - eks_nodegroup_result.changed +# - name: ensure IAM instance role exists +# amazon.aws.iam_role: +# name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster +# assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}' +# state: present +# create_instance_profile: 'no' +# managed_policies: +# - AmazonEKSServicePolicy +# - AmazonEKSClusterPolicy +# register: iam_role + +# - name: create a VPC to work in +# amazon.aws.ec2_vpc_net: +# cidr_block: 10.0.0.0/16 +# state: present +# name: '{{ resource_prefix }}_aws_eks' +# resource_tags: +# Name: '{{ resource_prefix }}_aws_eks' +# register: setup_vpc + +# - name: create subnets +# amazon.aws.ec2_vpc_subnet: +# az: '{{ aws_region }}{{ item.zone }}' +# tags: '{ "Name": "{{ resource_prefix }}_aws_eks-subnet-{{ item.type }}-{{ item.zone }}" }' +# vpc_id: '{{ setup_vpc.vpc.id }}' +# cidr: '{{ item.cidr }}' +# map_public: 'yes' +# state: present +# register: setup_subnets +# with_items: +# - '{{ eks_subnets }}' + +# - name: create Internet Gateway +# amazon.aws.ec2_vpc_igw: +# vpc_id: '{{ setup_vpc.vpc.id }}' +# state: present +# tags: +# Name: '{{ resource_prefix }}_IGW' +# register: setup_igw + +# - name: Set up public subnet route table +# community.aws.ec2_vpc_route_table: +# vpc_id: '{{ setup_vpc.vpc.id }}' +# tags: +# Name: "EKS-ng-{{ tiny_prefix }}" +# subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' +# routes: +# - dest: 0.0.0.0/0 +# gateway_id: '{{ setup_igw.gateway_id }}' +# register: public_route_table + +# - name: create security groups to use for EKS +# amazon.aws.ec2_security_group: +# name: '{{ item.name }}' +# description: '{{ item.description }}' +# state: present +# rules: '{{ item.rules }}' +# rules_egress: '{{ item.rules_egress|default(omit) }}' +# vpc_id: '{{ setup_vpc.vpc.id }}' +# with_items: '{{ eks_security_groups }}' +# register: setup_security_groups + +# - name: create EKS cluster +# community.aws.eks_cluster: +# name: '{{ eks_cluster_name }}' +# security_groups: '{{ eks_security_groups | map(attribute=''name'') }}' +# subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' +# role_arn: '{{ iam_role.iam_role.arn }}' +# version: 1.32 +# wait: true +# register: eks_create + +# - name: check that EKS cluster was created +# assert: +# that: +# - eks_create.name == eks_cluster_name + +# # Dependecies to eks nodegroup +# - name: create IAM instance role +# amazon.aws.iam_role: +# name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng' +# assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}' +# state: present +# create_instance_profile: no +# managed_policies: +# - AmazonEKSWorkerNodePolicy +# - AmazonEC2ContainerRegistryReadOnly +# - AmazonEKS_CNI_Policy +# register: iam_role_eks_nodegroup + +# - name: Pause a few seconds to ensure IAM role is available to next task +# pause: +# seconds: 10 + +# - name: Create securitygroup for node access +# amazon.aws.ec2_security_group: +# name: 'ansible-test-eks_nodegroup' +# description: "SSH access" +# vpc_id: '{{ setup_vpc.vpc.id }}' +# rules: +# - proto: tcp +# ports: +# - 22 +# cidr_ip: 0.0.0.0/0 +# register: securitygroup_eks_nodegroup + +# - name: Create Keypair for Access to Nodegroup nodes +# amazon.aws.ec2_key: +# name: "ansible-test-eks_nodegroup" +# register: ec2_key_eks_nodegroup + +# - name: create nodegroup (check mode) +# community.aws.eks_nodegroup: +# name: '{{ eks_nodegroup_name_a }}' +# state: present +# cluster_name: '{{ eks_cluster_name }}' +# node_role: '{{ iam_role_eks_nodegroup.iam_role.arn }}' +# subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' +# scaling_config: +# min_size: 1 +# max_size: 3 +# desired_size: 2 +# disk_size: 30 +# instance_types: ['t3.small'] +# ami_type: '{{ eks_nodegroup_ami_type }}' +# update_config: +# max_unavailable_percentage: 50 +# labels: +# 'env': 'test' +# taints: +# - key: 'env' +# value: 'test' +# effect: 'PREFER_NO_SCHEDULE' +# capacity_type: 'SPOT' +# tags: +# 'foo': 'bar' +# remote_access: +# ec2_ssh_key: "{{ ec2_key_eks_nodegroup.key.name }}" +# source_sg: +# - "{{ securitygroup_eks_nodegroup.group_id }}" +# wait: False +# register: eks_nodegroup_result +# check_mode: True + +# - name: check that eks_nodegroup is created (check mode) +# assert: +# that: +# - eks_nodegroup_result.changed - name: create IAM role for Pod Identity amazon.aws.iam_role: @@ -161,12 +161,34 @@ - name: Create policy from file amazon.aws.iam_policy: iam_type: role - iam_name: "{{ pod_identity_association_role.role_name }}" + iam_name: "{{ pod_identity_association_role.iam_role.role_name }}" policy_name: 'ansible-test-{{ tiny_prefix }}-eks-pod-identity-association' state: present policy_json: "{{ lookup('template', 'eks-pod-identity-association-policy.json.j2') }}" register: pod_identity_association_policy +- name: create replacement IAM role for Pod Identity + amazon.aws.iam_role: + name: 'ansible-test-{{ tiny_prefix }}-epia-replacement' + assume_role_policy_document: '{{ lookup(''file'',''eks-pod-identity-association-trust-policy.json'') }}' + state: present + create_instance_profile: no + managed_policies: [] + register: pod_identity_association_role_replacement + +- name: Create policy from file for replacement role + amazon.aws.iam_policy: + iam_type: role + iam_name: "{{ pod_identity_association_role_replacement.iam_role.role_name }}" + policy_name: 'ansible-test-{{ tiny_prefix }}-epia-replacement' + state: present + policy_json: "{{ lookup('template', 'eks-pod-identity-association-policy.json.j2') }}" + register: pod_identity_association_policy_replacement + - name: Create Kubeconfig cluster file command: > - aws eks update-kubeconfig --region {{ region }} --name {{ eks_cluster_name }} \ No newline at end of file + aws eks update-kubeconfig --region {{ aws_region }} --name {{ eks_cluster_name }} + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + AWS_SESSION_TOKEN: "{{ security_token | default(omit) }}" \ No newline at end of file diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml b/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml index daca163c9c6..c09a7902564 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/full_test.yml @@ -3,18 +3,13 @@ - name: Create pod identity association (check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + role_arn: "{{ pod_identity_association_role.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association is created (check mode) @@ -26,18 +21,13 @@ - name: Create pod identity association community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + role_arn: "{{ pod_identity_association_role.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association is created assert: @@ -47,18 +37,13 @@ - name: Create pod identity association (idempotency)(check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + role_arn: "{{ pod_identity_association_role.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association is not changed (idempotency)(check mode) @@ -70,38 +55,104 @@ - name: Create pod identity association (idempotency) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + role_arn: "{{ pod_identity_association_role.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association is not changed (idempotency) assert: that: - not pod_identity_result.changed +## +# info +- name: Get pod identity association info for non existing cluster + community.aws.eks_pod_identity_association_info: + cluster_name: 'NoSuchCluster' + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + register: pod_identity_info_result + ignore_errors: true + +- name: check that eks_pod_identity_association failed + assert: + that: + - not pod_identity_info_result.changed + - pod_identity_info_result is failed + +- name: Get pod identity association info for non existing namespace + community.aws.eks_pod_identity_association_info: + cluster_name: '{{ eks_cluster_name }}' + namespace: "no-such-namespace" + service_account: "{{ k8s_service_account }}" + register: pod_identity_info_result + ignore_errors: true + +- name: check that eks_pod_identity_association failed + assert: + that: + - not pod_identity_info_result.changed + - pod_identity_info_result is failed + +- name: Get pod identity association info for non existing service account + community.aws.eks_pod_identity_association_info: + cluster_name: '{{ eks_cluster_name }}' + namespace: "{{ k8s_namespace }}" + service_account: "no-such-sa" + register: pod_identity_info_result + ignore_errors: true + +- name: check that eks_pod_identity_association failed + assert: + that: + - not pod_identity_info_result.changed + - pod_identity_info_result is failed + +- name: Get pod identity association info for non existing association id + community.aws.eks_pod_identity_association_info: + cluster_name: '{{ eks_cluster_name }}' + association_id: "a-a1b2c3d4e5f6g7h8i" + register: pod_identity_info_result + ignore_errors: true + +- name: check that eks_pod_identity_association failed + assert: + that: + - not pod_identity_info_result.changed + - pod_identity_info_result is failed + +- name: Get pod identity association info with conflicting parameters + community.aws.eks_pod_identity_association_info: + cluster_name: '{{ eks_cluster_name }}' + namespace: "{{ k8s_namespace }}" + service_account: "{{ k8s_service_account }}" + association_id: "{{ pod_identity_result.association.association_id }}" + register: pod_identity_info_result + ignore_errors: true + +- name: Get pod identity association info with missing parameters + community.aws.eks_pod_identity_association_info: + cluster_name: '{{ eks_cluster_name }}' + namespace: "{{ k8s_namespace }}" + register: pod_identity_info_result + ignore_errors: true + - name: Get pod identity association info community.aws.eks_pod_identity_association_info: cluster_name: '{{ eks_cluster_name }}' namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" register: pod_identity_result_i1 - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association_info succeeds and returns same results assert: that: - - pod_identity_result_i1.changed - - pod_identity_result_i1.association_id == pod_identity_result.association_id + - not pod_identity_result_i1.changed + - pod_identity_result_i1.association.association_id == pod_identity_result.association.association_id ### # Update ignored @@ -109,18 +160,13 @@ - name: Test - attempt to update association with ignored parameter (tags) (check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + role_arn: "{{ pod_identity_association_role.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'bar': 'foo' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association did nothing (check mode) @@ -131,18 +177,13 @@ - name: Test - attempt to update association with ignored parameter (tags) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '123456789012') }}" + role_arn: "{{ pod_identity_association_role.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'bar': 'foo' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association did nothing assert: @@ -151,22 +192,16 @@ ### # Update - -- name: Test - attempt to update association with parameter (taregt_role_arn) (check mode) +- name: Test - attempt to update association with parameter (role_arn) (check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association is updated (check mode) @@ -174,42 +209,32 @@ that: - pod_identity_result.changed -- name: Test - attempt to update association with parameter (taregt_role_arn) +- name: Test - attempt to update association with parameter (role_arn) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association is updated assert: that: - pod_identity_result.changed -- name: Test - attempt to update association with parameter (taregt_role_arn) (check mode) +- name: Test - attempt to update association with parameter (role_arn) (idempotency)(check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association did nothing (check mode) @@ -217,21 +242,16 @@ that: - not pod_identity_result.changed -- name: Test - attempt to update association with parameter (taregt_role_arn) (idempotency) +- name: Test - attempt to update association with parameter (role_arn) (idempotency) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: present register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association did nothing assert: @@ -244,18 +264,13 @@ - name: Delete association (check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: absent register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association is deleted (check mode) @@ -266,18 +281,13 @@ - name: Delete association community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: absent register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association is deleted assert: @@ -287,18 +297,13 @@ - name: Delete association (idempotency)(check mode) community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: absent register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' check_mode: True - name: check that eks_pod_identity_association is not changed (check mode) @@ -309,18 +314,13 @@ - name: Delete association community.aws.eks_pod_identity_association: cluster_name: '{{ eks_cluster_name }}' - role_arn: "{{ pod_identity_association_role.arn }}" - taregt_role_arn: "{{ pod_identity_association_role.arn | replace(account_id, '120987654321') }}" + role_arn: "{{ pod_identity_association_role_replacement.iam_role.arn }}" namespace: "{{ k8s_namespace }}" service_account: "{{ k8s_service_account }}" tags: 'foo': 'bar' state: absent register: pod_identity_result - variables: - account_id: "{{ (pod_identity_association_role.arn | split(':'))[2] }}" - environment: - AWS_DEFAULT_REGION: 'us-east-1' - name: check that eks_pod_identity_association is not changed assert: diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml b/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml index c6db6028f49..ba3fa5f56b6 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/k8s_depedencies.yml @@ -4,6 +4,10 @@ api_version: v1 kind: Namespace state: present + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + AWS_SESSION_TOKEN: "{{ security_token | default(omit) }}" - name: Create a ServiceAccount object from an inline definition kubernetes.core.k8s: @@ -14,3 +18,7 @@ metadata: name: "{{ k8s_service_account }}" namespace: "{{ k8s_namespace }}" + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + AWS_SESSION_TOKEN: "{{ security_token | default(omit) }}" \ No newline at end of file diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/main.yml b/tests/integration/targets/eks_pod_identity_association/tasks/main.yml index ac9a5b86afe..078fda697df 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/main.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/main.yml @@ -9,10 +9,10 @@ access_key: '{{ aws_access_key }}' secret_key: '{{ aws_secret_key }}' session_token: '{{ security_token | default(omit) }}' - region: "{{ aws_region | default('us-east-1') }}" + region: "{{ aws_region }}" block: - include_tasks: dependecies.yml - - include_tasks: k8s_dependencies.yml + - include_tasks: k8s_depedencies.yml - include_tasks: full_test.yml always: - include_tasks: cleanup.yml From 391a6ace52f59e1396b9804fe84ac074ce7d6d92 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Wed, 17 Dec 2025 16:33:52 -0500 Subject: [PATCH 6/8] chore: cleanups Signed-off-by: Ali AlKhalidi --- .../modules/eks_pod_identity_association.py | 33 ++++++++----------- .../eks_pod_identity_association_info.py | 4 +-- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/plugins/modules/eks_pod_identity_association.py b/plugins/modules/eks_pod_identity_association.py index 643ade62dd3..f1b09fd42f9 100644 --- a/plugins/modules/eks_pod_identity_association.py +++ b/plugins/modules/eks_pod_identity_association.py @@ -24,10 +24,6 @@ description: ARN of IAM role to associate with the service account. type: str required: true - target_role_arn: - description: ARN of IAM target role to associate with the service account. - type: str - required: false namespace: description: - EKS Kubernetes namespace inside the cluster to create the association in. @@ -68,7 +64,19 @@ role_arn: arn:aws:iam:us-east-1:1231231123:role/abcd namespace: test-ns service_account: test-sa + tags: + foo: bar state: present + +- name: Delete pod identity association + community.aws.eks_pod_identity_association: + cluster_name: myeks + role_arn: arn:aws:iam:us-east-1:1231231123:role/abcd + namespace: test-ns + service_account: test-sa + tags: + foo: bar + state: absent """ RETURN = r""" @@ -82,11 +90,6 @@ returned: when state is present type: str sample: arn:aws:iam:us-east-1:1231231123:role/abcd -target_role_arn: - description: ARN of the target IAM role to associate with the service account. - returned: when state is present - type: str - sample: arn:aws:iam:us-east-1:1231231123:role/abcd namespace: description: The name of the Kubernetes namespace inside the cluster to create the association in. returned: when state present @@ -106,18 +109,13 @@ description: The ID of the association. returned: when state present type: str - sample: TBD + sample: a-a1b2c3d4e5f6g7h8i tags: description: Metadata that assists with categorization and organization. returned: when state present type: dict sample: foo: bar -external_id: - description: The unique identifier for this EKS Pod Identity association for a target IAM role. - returned: when state present - type: str - sample: TBD created_at: description: Association creation date and time. returned: when state is present @@ -128,11 +126,6 @@ returned: when state is present type: str sample: '2022-01-18T20:00:00.111000+00:00' -owner_arn: - description: If defined, the EKS Pod Identity association is owned by an Amazon EKS add-on. - returned: when state present - type: str - sample: TBD """ try: diff --git a/plugins/modules/eks_pod_identity_association_info.py b/plugins/modules/eks_pod_identity_association_info.py index 9579f7aa7a3..78dc928726b 100644 --- a/plugins/modules/eks_pod_identity_association_info.py +++ b/plugins/modules/eks_pod_identity_association_info.py @@ -34,7 +34,6 @@ - Ignore when association Id is provided. - Must be coupled with namespace. type: str - extends_documentation_fragment: - amazon.aws.boto3 - amazon.aws.common.modules @@ -45,8 +44,9 @@ - name: get current pod identity association settings by id community.aws.eks_pod_identity_association_info: cluster_name: myeks - association_id: "aws-pod-identity-association-id" + association_id: a-a1b2c3d4e5f6g7h8i register: association_info + - name: get current pod identity association settings by service account and namespace community.aws.eks_pod_identity_association_info: cluster_name: myeks From 33e016cafec7b1fb4bd0e2859a2f523a1f6d9426 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Wed, 17 Dec 2025 18:53:23 -0500 Subject: [PATCH 7/8] fix: ignore errors for cleanup tasks Signed-off-by: Ali AlKhalidi --- .../targets/eks_pod_identity_association/tasks/cleanup.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml index 11cae1751c3..52bef9ed099 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/cleanup.yml @@ -74,11 +74,13 @@ vpc_id: '{{ setup_vpc.vpc.id }}' rules: [] state: absent + ignore_errors: true - name: Delete Keypair for Access to Nodegroup nodes amazon.aws.ec2_key: name: "ansible-test-eks_nodegroup" state: absent + ignore_errors: true - name: remove Route Tables amazon.aws.ec2_vpc_route_table: From a2624ade7425b830181b123bd77e20ffc426c009 Mon Sep 17 00:00:00 2001 From: Ali AlKhalidi Date: Wed, 17 Dec 2025 19:02:55 -0500 Subject: [PATCH 8/8] fix: add back EKS tasks Signed-off-by: Ali AlKhalidi --- .../tasks/dependecies.yml | 299 +++++++++--------- 1 file changed, 149 insertions(+), 150 deletions(-) diff --git a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml index 2d472a123f7..7e9ec096a66 100644 --- a/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml +++ b/tests/integration/targets/eks_pod_identity_association/tasks/dependecies.yml @@ -1,153 +1,152 @@ -# Create a EKS Cluster to test Nodegroup -# This space was a copy by aws_eks_cluster integration test -# - name: ensure IAM instance role exists -# amazon.aws.iam_role: -# name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster -# assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}' -# state: present -# create_instance_profile: 'no' -# managed_policies: -# - AmazonEKSServicePolicy -# - AmazonEKSClusterPolicy -# register: iam_role - -# - name: create a VPC to work in -# amazon.aws.ec2_vpc_net: -# cidr_block: 10.0.0.0/16 -# state: present -# name: '{{ resource_prefix }}_aws_eks' -# resource_tags: -# Name: '{{ resource_prefix }}_aws_eks' -# register: setup_vpc - -# - name: create subnets -# amazon.aws.ec2_vpc_subnet: -# az: '{{ aws_region }}{{ item.zone }}' -# tags: '{ "Name": "{{ resource_prefix }}_aws_eks-subnet-{{ item.type }}-{{ item.zone }}" }' -# vpc_id: '{{ setup_vpc.vpc.id }}' -# cidr: '{{ item.cidr }}' -# map_public: 'yes' -# state: present -# register: setup_subnets -# with_items: -# - '{{ eks_subnets }}' - -# - name: create Internet Gateway -# amazon.aws.ec2_vpc_igw: -# vpc_id: '{{ setup_vpc.vpc.id }}' -# state: present -# tags: -# Name: '{{ resource_prefix }}_IGW' -# register: setup_igw - -# - name: Set up public subnet route table -# community.aws.ec2_vpc_route_table: -# vpc_id: '{{ setup_vpc.vpc.id }}' -# tags: -# Name: "EKS-ng-{{ tiny_prefix }}" -# subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' -# routes: -# - dest: 0.0.0.0/0 -# gateway_id: '{{ setup_igw.gateway_id }}' -# register: public_route_table - -# - name: create security groups to use for EKS -# amazon.aws.ec2_security_group: -# name: '{{ item.name }}' -# description: '{{ item.description }}' -# state: present -# rules: '{{ item.rules }}' -# rules_egress: '{{ item.rules_egress|default(omit) }}' -# vpc_id: '{{ setup_vpc.vpc.id }}' -# with_items: '{{ eks_security_groups }}' -# register: setup_security_groups - -# - name: create EKS cluster -# community.aws.eks_cluster: -# name: '{{ eks_cluster_name }}' -# security_groups: '{{ eks_security_groups | map(attribute=''name'') }}' -# subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' -# role_arn: '{{ iam_role.iam_role.arn }}' -# version: 1.32 -# wait: true -# register: eks_create - -# - name: check that EKS cluster was created -# assert: -# that: -# - eks_create.name == eks_cluster_name - -# # Dependecies to eks nodegroup -# - name: create IAM instance role -# amazon.aws.iam_role: -# name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng' -# assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}' -# state: present -# create_instance_profile: no -# managed_policies: -# - AmazonEKSWorkerNodePolicy -# - AmazonEC2ContainerRegistryReadOnly -# - AmazonEKS_CNI_Policy -# register: iam_role_eks_nodegroup - -# - name: Pause a few seconds to ensure IAM role is available to next task -# pause: -# seconds: 10 - -# - name: Create securitygroup for node access -# amazon.aws.ec2_security_group: -# name: 'ansible-test-eks_nodegroup' -# description: "SSH access" -# vpc_id: '{{ setup_vpc.vpc.id }}' -# rules: -# - proto: tcp -# ports: -# - 22 -# cidr_ip: 0.0.0.0/0 -# register: securitygroup_eks_nodegroup - -# - name: Create Keypair for Access to Nodegroup nodes -# amazon.aws.ec2_key: -# name: "ansible-test-eks_nodegroup" -# register: ec2_key_eks_nodegroup - -# - name: create nodegroup (check mode) -# community.aws.eks_nodegroup: -# name: '{{ eks_nodegroup_name_a }}' -# state: present -# cluster_name: '{{ eks_cluster_name }}' -# node_role: '{{ iam_role_eks_nodegroup.iam_role.arn }}' -# subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' -# scaling_config: -# min_size: 1 -# max_size: 3 -# desired_size: 2 -# disk_size: 30 -# instance_types: ['t3.small'] -# ami_type: '{{ eks_nodegroup_ami_type }}' -# update_config: -# max_unavailable_percentage: 50 -# labels: -# 'env': 'test' -# taints: -# - key: 'env' -# value: 'test' -# effect: 'PREFER_NO_SCHEDULE' -# capacity_type: 'SPOT' -# tags: -# 'foo': 'bar' -# remote_access: -# ec2_ssh_key: "{{ ec2_key_eks_nodegroup.key.name }}" -# source_sg: -# - "{{ securitygroup_eks_nodegroup.group_id }}" -# wait: False -# register: eks_nodegroup_result -# check_mode: True - -# - name: check that eks_nodegroup is created (check mode) -# assert: -# that: -# - eks_nodegroup_result.changed +# Create a EKS Cluster and NodeGroup to test pod identity association +# This space was a copy by eks_nodegroup integration test +- name: ensure IAM instance role exists + amazon.aws.iam_role: + name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster + assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}' + state: present + create_instance_profile: 'no' + managed_policies: + - AmazonEKSServicePolicy + - AmazonEKSClusterPolicy + register: iam_role + +- name: create a VPC to work in + amazon.aws.ec2_vpc_net: + cidr_block: 10.0.0.0/16 + state: present + name: '{{ resource_prefix }}_aws_eks' + resource_tags: + Name: '{{ resource_prefix }}_aws_eks' + register: setup_vpc + +- name: create subnets + amazon.aws.ec2_vpc_subnet: + az: '{{ aws_region }}{{ item.zone }}' + tags: '{ "Name": "{{ resource_prefix }}_aws_eks-subnet-{{ item.type }}-{{ item.zone }}" }' + vpc_id: '{{ setup_vpc.vpc.id }}' + cidr: '{{ item.cidr }}' + map_public: 'yes' + state: present + register: setup_subnets + with_items: + - '{{ eks_subnets }}' + +- name: create Internet Gateway + amazon.aws.ec2_vpc_igw: + vpc_id: '{{ setup_vpc.vpc.id }}' + state: present + tags: + Name: '{{ resource_prefix }}_IGW' + register: setup_igw + +- name: Set up public subnet route table + community.aws.ec2_vpc_route_table: + vpc_id: '{{ setup_vpc.vpc.id }}' + tags: + Name: "EKS-ng-{{ tiny_prefix }}" + subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' + routes: + - dest: 0.0.0.0/0 + gateway_id: '{{ setup_igw.gateway_id }}' + register: public_route_table + +- name: create security groups to use for EKS + amazon.aws.ec2_security_group: + name: '{{ item.name }}' + description: '{{ item.description }}' + state: present + rules: '{{ item.rules }}' + rules_egress: '{{ item.rules_egress|default(omit) }}' + vpc_id: '{{ setup_vpc.vpc.id }}' + with_items: '{{ eks_security_groups }}' + register: setup_security_groups + +- name: create EKS cluster + community.aws.eks_cluster: + name: '{{ eks_cluster_name }}' + security_groups: '{{ eks_security_groups | map(attribute=''name'') }}' + subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' + role_arn: '{{ iam_role.iam_role.arn }}' + version: 1.32 + wait: true + register: eks_create + +- name: check that EKS cluster was created + assert: + that: + - eks_create.name == eks_cluster_name + +# Dependecies to eks nodegroup +- name: create IAM instance role + amazon.aws.iam_role: + name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng' + assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}' + state: present + create_instance_profile: no + managed_policies: + - AmazonEKSWorkerNodePolicy + - AmazonEC2ContainerRegistryReadOnly + - AmazonEKS_CNI_Policy + register: iam_role_eks_nodegroup + +- name: Pause a few seconds to ensure IAM role is available to next task + pause: + seconds: 10 + +- name: Create securitygroup for node access + amazon.aws.ec2_security_group: + name: 'ansible-test-eks_nodegroup' + description: "SSH access" + vpc_id: '{{ setup_vpc.vpc.id }}' + rules: + - proto: tcp + ports: + - 22 + cidr_ip: 0.0.0.0/0 + register: securitygroup_eks_nodegroup + +- name: Create Keypair for Access to Nodegroup nodes + amazon.aws.ec2_key: + name: "ansible-test-eks_nodegroup" + register: ec2_key_eks_nodegroup + +- name: create nodegroup + community.aws.eks_nodegroup: + name: '{{ eks_nodegroup_name_a }}' + state: present + cluster_name: '{{ eks_cluster_name }}' + node_role: '{{ iam_role_eks_nodegroup.iam_role.arn }}' + subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}' + scaling_config: + min_size: 1 + max_size: 3 + desired_size: 2 + disk_size: 30 + instance_types: ['t3.small'] + ami_type: '{{ eks_nodegroup_ami_type }}' + update_config: + max_unavailable_percentage: 50 + labels: + 'env': 'test' + taints: + - key: 'env' + value: 'test' + effect: 'PREFER_NO_SCHEDULE' + capacity_type: 'SPOT' + tags: + 'foo': 'bar' + remote_access: + ec2_ssh_key: "{{ ec2_key_eks_nodegroup.key.name }}" + source_sg: + - "{{ securitygroup_eks_nodegroup.group_id }}" + wait: False + register: eks_nodegroup_result + +- name: check that eks_nodegroup is created + assert: + that: + - eks_nodegroup_result.changed - name: create IAM role for Pod Identity amazon.aws.iam_role: