Using Lambda to Automate OIDC and IAM role for Service Account in EKS

You possibly can automate the OIDC and IAM roles creation if you provision EKS cluster by Terraform or CloudFormatio however what if you wish to automate the creation of OIDC and IAM roles when creating the EKS cluster by Rancher!

What if you wish to use a crossplane to create AWS assets from a brand new EKS cluster, how does crossplane get entry to the cluster, now we face a chicken-egg downside.

On this article, I’m going to indicate you the best way to Automate the method as soon as the EKS cluster is created.

We want OIDC and IAM roles to make use of service accounts in Kubernetes to get entry to AWS assets like S3, SQS,SNS ..and many others

AWS is really helpful to make use of service accounts fairly than utilizing
static ACCESS KEY and SECRET KEY inside your pods.

Within the structure diagram when a brand new EKS cluster is created then it would ship an occasion to the occasion bridge after which we added a rule to invoke lambda solely when the occasion title is CreateNodegroup or DeleteCluster.
You’ll ask why the occasion title just isn’t CreateCluster as a result of we’re concerned about values after the cluster is created, the creation of the cluster takes round 8 minutes.

Steps:

1- Go to lambda service -> Create operate -> Add “eks-iam” within the Perform title -> Creator from scratch -> select Runtime Python 3.8 -> Create a brand new position with fundamental Lambda permissions -> Create operate

2- Create IAM a coverage eks-iam-policy and add the under coverage

{
    "Model": "2012-10-17",
    "Assertion": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:UntagRole",
                "iam:TagRole",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:AttachRolePolicy",
                "iam:CreateOpenIDConnectProvider",
                "iam:DetachRolePolicy",
                "iam:ListAttachedRolePolicies",
                "eks:DescribeCluster",
                "iam:UntagOpenIDConnectProvider",
                "eks:ListClusters",
                "iam:DeleteOpenIDConnectProvider",
                "iam:TagOpenIDConnectProvider"
            ],
            "Useful resource": "*"
        }
    ]
}
Enter fullscreen mode

Exit fullscreen mode

3- Connect the coverage to the lambda Execution position, go to lambda eks-iam operate -> Configuration -> Permissions -> Execution position -> click on on Position title eks-iam-role-XXXX -> connect coverage eks-iam-policy

4- Add the under code to eks-iam lambda operate

import json
import boto3

# through which namespace that utilized by the service account
namespace="default"

# iam insurance policies
insurance policies = ['arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess']

iam = boto3.consumer('iam')

def create_role(roleName,coverage):
    response = iam.create_role(
        RoleName=roleName,
        AssumeRolePolicyDocument=json.dumps(coverage),
        Description='Lambda invoked by Rancher occasion to Create this Position',
        MaxSessionDuration=3600,
        Tags=[
            {
                'Key': 'Created-By',
                'Value': 'Lambda'
            },

        ]
    )

    return response

def lambda_handler(occasion, context):

    if occasion['detail']['eventName'] == "CreateNodegroup":
        clusterName = occasion['detail']['responseElements']['nodegroup']['clusterName']
        eks = boto3.consumer('eks')
        eksResponse = eks.describe_cluster(title=clusterName)
        oidc = eksResponse['cluster']['identity']['oidc']['issuer']

        # create oidc supplier
        oidcResponse = iam.create_open_id_connect_provider(Url=oidc,
        ClientIDList=['sts.amazonaws.com',],
        ThumbprintList=['9e99a48a9960b14926bb7f3b02e22da2b0ab7280',],
        Tags=[{ 'Key': 'Created-By', 'Value': 'Lambda' }, ])

        arn = oidcResponse['OpenIDConnectProviderArn']
        coverage =  { "Model": "2012-10-17","Assertion": [ {"Sid": "", "Effect": "Allow", "Principal": { "Federated": arn}, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { arn.split('oidc-provider/')[1] +":sub": "system:serviceaccount:" + namespace + ":" + clusterName }}}]}

        # create iam position
        createResponse = create_role (clusterName, coverage)

        print(createResponse)

        # connect insurance policies to the position
        for i in vary(len(insurance policies)):
            iam.attach_role_policy(
                RoleName=clusterName,
                PolicyArn= insurance policies[i]
                )

        return oidcResponse

    elif occasion['detail']['eventName'] == "DeleteCluster":
        clusterName =  occasion['detail']['responseElements']['cluster']['name']
        oidc = occasion['detail']['responseElements']['cluster']['identity']['oidc']['issuer']
        accountId = occasion['detail']['userIdentity']['accountId']
        arn = "arn:aws:iam::" + accountId + ":oidc-provider/" + oidc.cut up('https://')[1]

        # take away oidc supplier
        oidcResponse = iam.delete_open_id_connect_provider(
            OpenIDConnectProviderArn=arn
            )

        # get all insurance policies connected to the position
        policyResponse = iam.list_attached_role_policies(
            RoleName=clusterName
            )

        # detach all insurance policies from the position
        for i in vary(len(policyResponse['AttachedPolicies'])):
            iam.detach_role_policy(
                RoleName=clusterName, PolicyArn=policyResponse['AttachedPolicies'][i]['PolicyArn']
                )

        # take away the iam position
        roleResponse = iam.delete_role(
            RoleName=clusterName
            )

        return oidcResponse

Enter fullscreen mode

Exit fullscreen mode

5- Go to EventBridge -> Guidelines -> Create Rule -> Rule with an occasion sample -> Within the Occasion sample, select Customized patterns (JSON editor) and add the next:

{
  "supply": ["aws.eks"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "element": {
    "eventSource": ["eks.amazonaws.com"],
    "eventName": ["CreateNodegroup", "DeleteCluster"]
  }
}
Enter fullscreen mode

Exit fullscreen mode

Select goal -> AWS service -> Choose a goal -> Lambda operate -> Perform -> eks-iam

6- Create a service account in your EKS cluster, now we will know the arn of our IAM position since you solely change the EKS-CLUSTER-NAME.

Trace: I assumed you’ve got a novel title for EKS clusters

---
apiVersion: v1
form: ServiceAccount
metadata:
  title: list-s3
  namespace: default
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::AWS-ACCOUNT-NUMBER:position/EKS-CLUSTER-NAME

Enter fullscreen mode

Exit fullscreen mode

7- Create a deployment and outline the service account title like the instance under

---
apiVersion: apps/v1
form: Deployment
metadata:
  title: aws-cli
  namespace: default
spec:
  selector:
    matchLabels:
      app: aws-cli
  replicas: 1
  template:
    metadata:
      labels:
        app: aws-cli
    spec:
      serviceAccountName: list-s3
      containers:
      - title: aws-cli
        picture: amazon/aws-cli
        command: [ "/bin/bash", "-c", "--" ]  
        args: [ "while true; do sleep 30; done;" ]

Enter fullscreen mode

Exit fullscreen mode

now you may entry your pod and take a look at it by:

aws s3 ls
Enter fullscreen mode

Exit fullscreen mode

In the long run, you may have a default coverage that’s connected for every EKS cluster after which use instruments like crossplane to create a selected IAM insurance policies and roles.

Add a Comment

Your email address will not be published. Required fields are marked *