Skip to content

For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.

Page as Markdown

    

Access AWS Lambda with a service account

Use AWS IAM Roles for Service Accounts (IRSA) to configure kgateway to invoke AWS Lambda functions. For more information about IRSA, see the AWS documentation.

About

You can set up Lambda function invocation in the following ways:

  • Single role: The gateway proxy service account assumes a single IAM role that has Lambda permissions directly attached. Use this method when your Lambda functions are in the same AWS account and you want a simple setup.
  • Role chaining: The gateway proxy service account assumes an authentication role, which in turn assumes a separate invocation role that has Lambda permissions. Use this method when you want to route to Lambda functions in a different AWS account, or when you want per-Backend least-privilege isolation without storing long-lived credentials.

In this guide, you follow these steps:

AWS resources:

  • Associate your EKS cluster with an IAM OIDC provider
  • Create IAM roles and policies for your chosen method
  • Deploy the Amazon EKS Pod Identity Webhook to your cluster
  • Create a Lambda function for testing

Kgateway resources:

  • Install kgateway
  • Annotate the gateway proxy service account with the IAM role
  • Set up routing to your function by creating Backend and HTTPRoute resources

Before you begin

Warning

This guide requires you to enable IAM settings in your EKS cluster, such as the AWS Pod Identity Webhook, before you deploy kgateway components that are created during installation, such as the Gateway CRD and the gateway proxy service account. You might use this guide with a fresh EKS test cluster to try out Lambda function invocation with kgateway service accounts.

Configure AWS IAM resources

Save your AWS details, and create the IAM roles and policies for the gateway proxy pod to use.

  1. Save the region where your Lambda functions exist, the region where your EKS cluster exists, your cluster name, and the ID of the AWS account.

    export AWS_LAMBDA_REGION=<lambda_function_region>
    export AWS_CLUSTER_REGION=<cluster_region>
    export CLUSTER_NAME=<cluster_name>
    export AWS_ACCOUNT_ID=<account_id>
  2. Save and verify your cluster’s OIDC provider details.

    1. Get the OIDC provider for your cluster, in the format oidc.eks.<region>.amazonaws.com/id/<cluster_id>.
      export OIDC_PROVIDER=$(aws eks describe-cluster --name ${CLUSTER_NAME} --region ${AWS_CLUSTER_REGION} --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
      echo $OIDC_PROVIDER
    2. Verify that the OIDC provider’s ARN is listed as an entry in AWS IAM.
      aws iam list-open-id-connect-providers \
        --query "OpenIDConnectProviderList[?contains(Arn, '${OIDC_PROVIDER}')].Arn" \
        --output text
      • If your OIDC provider is not returned, add it to IAM.
        aws iam create-open-id-connect-provider \
          --url "https://${OIDC_PROVIDER}" \
          --client-id-list sts.amazonaws.com \
          --thumbprint-list "$(openssl s_client -servername $(echo ${OIDC_PROVIDER} | cut -d/ -f1) -showcerts -connect $(echo ${OIDC_PROVIDER} | cut -d/ -f1):443 </dev/null 2>/dev/null | openssl x509 -fingerprint -noout -sha1 | cut -d= -f2 | tr -d ':')"
  3. Create an IAM policy to allow access to the following four Lambda actions. Note that the permissions to discover and invoke functions are listed in the same policy. In a more advanced setup, you might separate discovery and invocation permissions into two IAM policies.

    cat >policy.json <<EOF
    {
       "Version": "2012-10-17",
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "lambda:ListFunctions",
                   "lambda:InvokeFunction",
                   "lambda:GetFunction",
                   "lambda:InvokeAsync"
               ],
               "Resource": "*"
           }
       ]
    }
    EOF
    
    aws iam create-policy --policy-name lambda-policy --policy-document file://policy.json 
  4. Create an IAM role for the gateway proxy service account. Choose whether to attach Lambda permissions directly to the role, or use role chaining to have the proxy assume a separate target role at request time.

    Associate the Lambda policy directly with the gateway proxy IAM role. The proxy uses this role to invoke Lambda functions. For more information about these steps, see the AWS documentation.

    1. Create the following IAM role. Note that the service account name http in the kgateway-system namespace is specified, because in later steps you create an HTTP gateway named http.
      cat >role.json <<EOF
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
          },
          {
            "Effect": "Allow",
            "Principal": {
              "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
              "StringEquals": {
                "${OIDC_PROVIDER}:sub": "system:serviceaccount:kgateway-system:http"
              }
            }
          }
        ]
      }
      EOF
      
      aws iam create-role --role-name lambda-role --assume-role-policy-document file://role.json
    2. Attach the IAM role to the IAM policy. This IAM role for the service account is known as an IRSA.
      aws iam attach-role-policy --role-name lambda-role --policy-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:policy/lambda-policy
    3. Verify that the policy is attached to the role.
      aws iam list-attached-role-policies --role-name lambda-role
      Example output:
      {
          "AttachedPolicies": [
              {
                  "PolicyName": "lambda-policy",
                  "PolicyArn": "arn:aws:iam::111122223333:policy/lambda-policy"
              }
          ]
      }
    4. Save the role ARN for later use.
      export ROLE_ARN=$(aws iam get-role --role-name lambda-role --query 'Role.Arn' --output text)
      echo $ROLE_ARN

Deploy the Amazon EKS Pod Identity Webhook

Before you install kgateway, deploy the Amazon EKS Pod Identity Webhook, which allows pods’ service accounts to use AWS IAM roles. When you create the kgateway proxy in the next section, this webhook mutates the proxy’s service account so that it can assume your IAM role to invoke Lambda functions.

  1. In your EKS cluster, install cert-manager, which is a prerequisite for the webhook.

    wget https://github.com/cert-manager/cert-manager/releases/download/v1.12.4/cert-manager.yaml
    kubectl apply -f cert-manager.yaml
  2. Verify that all cert-manager pods are running.

    kubectl get pods -n cert-manager
  3. Deploy the Amazon EKS Pod Identity Webhook.

    kubectl apply -f https://raw.githubusercontent.com/solo-io/workshops/refs/heads/master/kgateway/2-1/default/data/steps/deploy-amazon-pod-identity-webhook/auth.yaml
    kubectl apply -f https://raw.githubusercontent.com/solo-io/workshops/refs/heads/master/kgateway/2-1/default/data/steps/deploy-amazon-pod-identity-webhook/deployment-base.yaml
    kubectl apply -f https://raw.githubusercontent.com/solo-io/workshops/refs/heads/master/kgateway/2-1/default/data/steps/deploy-amazon-pod-identity-webhook/mutatingwebhook.yaml
    kubectl apply -f https://raw.githubusercontent.com/solo-io/workshops/refs/heads/master/kgateway/2-1/default/data/steps/deploy-amazon-pod-identity-webhook/service.yaml
  4. Verify that the webhook deployment completes.

    kubectl rollout status deploy/pod-identity-webhook

Install kgateway

Be sure that you deployed the Amazon EKS Pod Identity Webhook to your cluster first before you continue to install kgateway.

  1. Deploy the Kubernetes Gateway API CRDs.

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml
  2. Deploy the kgateway CRDs by using Helm.

    helm upgrade -i kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \
    --create-namespace --namespace kgateway-system \
    --version v2.4.0 \
    --set controller.image.pullPolicy=Always
  3. Install kgateway by using Helm.

    helm upgrade -i kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \
    --namespace kgateway-system \
    --version v2.4.0 \
    --set controller.image.pullPolicy=Always
  4. Make sure that the kgateway control plane is running.

    kubectl get pods -n kgateway-system

    Example output:

    NAME                        READY   STATUS    RESTARTS   AGE
    kgateway-5495d98459-46dpk   1/1     Running   0          19s
    

Annotate the gateway proxy service account

  1. Create a GatewayParameters resource to specify the eks.amazonaws.com/role-arn IRSA annotation for the gateway proxy service account.

    kubectl apply -f- <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: GatewayParameters
    metadata:
      name: http-lambda
      namespace: kgateway-system
    spec:
      kube:
        serviceAccount:
          extraAnnotations:
            eks.amazonaws.com/role-arn: ${ROLE_ARN}
    EOF
  2. Create the following http Gateway resource, which includes a reference to the http-lambda GatewayParameters.

    kubectl apply -f- <<EOF
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: http
      namespace: kgateway-system
      annotations:
    spec:
      gatewayClassName: kgateway
      infrastructure:
        parametersRef:
          name: http-lambda
          group: gateway.kgateway.dev
          kind: GatewayParameters        
      listeners:
      - protocol: HTTP
        port: 8080
        name: http
        allowedRoutes:
          namespaces:
            from: All
    EOF
  3. Check the status of the gateway to make sure that your configuration is accepted. Note that in the output, a NoConflicts status of False indicates that the gateway is accepted and does not conflict with other gateway configuration.

    kubectl get gateway http -n kgateway-system -o yaml
  4. Verify that the http service account has the eks.amazonaws.com/role-arn: ${ROLE_ARN} annotation.

    kubectl describe serviceaccount http -n kgateway-system

Create a Lambda function

Create an AWS Lambda function to test kgateway routing.

  1. Log in to the AWS console and navigate to the Lambda page.

  2. Click the Create Function button.

  3. Name the function echo and click Create function.

  4. Replace the default contents of index.mjs with the following Node.js function, which returns a response body that contains exactly what was sent to the function in the request body.

    export const handler = async(event) => {
        const response = {
            statusCode: 200,
            body: `Response from AWS Lambda. Here's the request you just sent me: ${JSON.stringify(event)}`
        };
        return response;
    };
  5. Click Deploy.

Set up routing to your function

Create Backend and HTTPRoute resources to route requests to the Lambda function.

  1. Create a Backend resource that references the AWS region, ID of the account that contains the IAM role, and echo function that you created.

    The Backend uses the proxy’s ambient IRSA credentials directly. No auth field is required.

    kubectl apply -f - <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: Backend
    metadata:
      name: lambda
      namespace: kgateway-system
    spec:
      type: AWS
      aws:
        region: ${AWS_LAMBDA_REGION}
        accountId: "${AWS_ACCOUNT_ID}"
        lambda:
          functionName: echo
    EOF
  2. Create an HTTPRoute resource that references the lambda Backend.

    kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: lambda
      namespace: kgateway-system
    spec:
      parentRefs:
        - name: http
          namespace: kgateway-system
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /echo
        backendRefs:
        - name: lambda
          namespace: kgateway-system
          group: gateway.kgateway.dev
          kind: Backend
    EOF
  3. Get the external address of the gateway and save it in an environment variable.

    export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
    echo $INGRESS_GW_ADDRESS   

  4. Confirm that kgateway correctly routes requests to Lambda by sending a curl request to the echo function. Note that the first request might take a few seconds to process, because the AWS Security Token Service (STS) credential request must be performed first. However, after the credentials are cached, subsequent requests are processed more quickly.

    curl -H "Host: lambda.${AWS_LAMBDA_REGION}.amazonaws.com" \
      $INGRESS_GW_ADDRESS:8080/echo \
      -d '{"key1":"value1", "key2":"value2"}' -X POST

    Example response:

    {"statusCode":200,"body":"Response from AWS Lambda. Here's the request you just sent me: {\"key1\":\"value1\",\"key2\":\"value2\"}"}% 

At this point, kgateway is routing directly to the echo Lambda function using an IRSA!

Cleanup

You can remove the resources that you created in this guide.

Resources for the echo function

  1. Delete the lambda HTTPRoute and lambda Backend.

    kubectl delete HTTPRoute lambda -n kgateway-system
    kubectl delete Backend lambda -n kgateway-system
  2. Use the AWS Lambda console to delete the echo test function.

IRSA authorization (optional)

If you no longer need to access Lambda functions from kgateway:

  1. Delete the GatewayParameters resources.

    kubectl delete GatewayParameters http-lambda -n kgateway-system
  2. Remove the reference to the http-lambda GatewayParameters from the http Gateway.

    kubectl apply -f- <<EOF
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: http
      namespace: kgateway-system
    spec:
      gatewayClassName: kgateway
      listeners:
      - protocol: HTTP
        port: 8080
        name: http
        allowedRoutes:
          namespaces:
            from: All
    EOF
  3. Delete the pod identity webhook.

    kubectl delete deploy pod-identity-webhook
  4. Remove cert-manager.

    kubectl delete -f cert-manager.yaml -n cert-manager
    kubectl delete ns cert-manager
  5. Delete the AWS IAM resources that you created.

    aws iam detach-role-policy --role-name lambda-role --policy-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:policy/lambda-policy
    aws iam delete-role --role-name lambda-role
    aws iam delete-policy --policy-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:policy/lambda-policy
Was this page helpful?