For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Access AWS Lambda with a service account
Use IAM Roles for Service Accounts (IRSA) to invoke AWS Lambda functions, with direct role attachment or cross-account role chaining.
Use AWS IAM Roles for Service Accounts (IRSA) to configure Solo Enterprise for 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
Solo Enterprise for kgateway resources:
- Install Solo Enterprise for kgateway
- Annotate the gateway proxy service account with the IAM role
- Set up routing to your function by creating
BackendandHTTPRouteresources
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 Solo Enterprise for 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 Solo Enterprise for 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.
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>Save and verify your cluster’s OIDC provider details.
- 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- If an OIDC provider is not returned, follow the AWS documentation to Create an IAM OIDC provider for your cluster, and then run this command again to save the OIDC provider in an environment variable.
- 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 ':')"
- If your OIDC provider is not returned, add it to IAM.
- Get the OIDC provider for your cluster, in the format
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.jsonCreate 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.
- Create the following IAM role. Note that the service account name
httpin thekgateway-systemnamespace is specified, because in later steps you create an HTTP gateway namedhttp.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 - 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 - Verify that the policy is attached to the role.Example output:
aws iam list-attached-role-policies --role-name lambda-role{ "AttachedPolicies": [ { "PolicyName": "lambda-policy", "PolicyArn": "arn:aws:iam::111122223333:policy/lambda-policy" } ] } - 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
This method involves defining two roles that the gateway proxy service account assumes via IRSA:
- Authentication: In the account that you want to use to authenticate with AWS (the “authentication account”), create a role that the gateway proxy service account assumes to securely access the Lambda account. Annotate the gateway proxy service account so that it can assume this role via IRSA.
- Invocation: In the account that contains the Lambda functions you want to route to (the “Lambda account”), create a role that the gateway’s assumed authentication role can use to invoke Lambda functions. Reference this role in the Backend resource.
Tip
If your Lambda functions are in the same AWS account that you authenticate with, set both
AUTH_ACCOUNT_IDandLAMBDA_ACCOUNT_IDto the same value.Save your authentication and Lambda account IDs.
export AUTH_ACCOUNT_ID=<authentication_account_id> export LAMBDA_ACCOUNT_ID=<lambda_account_id>In your authentication account, create the following resources.
- Create the gateway proxy IAM role with a trust policy scoped to the
httpservice account in thekgateway-systemnamespace.cat >proxy-role.json <<EOF { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::${AUTH_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 kgateway-proxy-role --assume-role-policy-document file://proxy-role.json - Save the proxy role ARN and grant it permission to assume the target Lambda invocation role.
export ROLE_ARN=$(aws iam get-role --role-name kgateway-proxy-role --query 'Role.Arn' --output text) echo $ROLE_ARN aws iam put-role-policy \ --role-name kgateway-proxy-role \ --policy-name allow-assume-lambda-role \ --policy-document "{ \"Version\": \"2012-10-17\", \"Statement\": [{ \"Effect\": \"Allow\", \"Action\": \"sts:AssumeRole\", \"Resource\": \"arn:aws:iam::${LAMBDA_ACCOUNT_ID}:role/lambda-invoke-role\" }] }"
- Create the gateway proxy IAM role with a trust policy scoped to the
In your Lambda account, create the following resources.
- Create an IAM policy that contains the Lambda permissions needed to invoke functions.
cat >invoke-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 kgateway-lambda-invoke-policy --policy-document file://invoke-policy.json - Create an IAM role that specifies the ARN of the authentication account’s proxy role. This ensures that the proxy role can assume this Lambda account role to invoke functions.
cat >invoke-role.json <<EOF { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "AWS": "${ROLE_ARN}" }, "Action": "sts:AssumeRole" }] } EOF aws iam create-role --role-name lambda-invoke-role --assume-role-policy-document file://invoke-role.json - Attach the invocation IAM role to the invocation IAM policy and save the role ARN.
aws iam attach-role-policy \ --role-name lambda-invoke-role \ --policy-arn=arn:aws:iam::${LAMBDA_ACCOUNT_ID}:policy/kgateway-lambda-invoke-policy export INVOKE_ROLE_ARN=$(aws iam get-role --role-name lambda-invoke-role --query 'Role.Arn' --output text) echo $INVOKE_ROLE_ARN
- Create an IAM policy that contains the Lambda permissions needed to invoke functions.
- Create the following IAM role. Note that the service account name
Deploy the Amazon EKS Pod Identity Webhook
Before you install Solo Enterprise for kgateway, deploy the Amazon EKS Pod Identity Webhook, which allows pods’ service accounts to use AWS IAM roles. When you create the Solo Enterprise for 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.
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.yamlVerify that all cert-manager pods are running.
kubectl get pods -n cert-managerDeploy 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.yamlVerify that the webhook deployment completes.
kubectl rollout status deploy/pod-identity-webhook
Install Solo Enterprise for kgateway
Be sure that you deployed the Amazon EKS Pod Identity Webhook to your cluster first before you continue to install Solo Enterprise for kgateway.
Set your Solo Enterprise for kgateway license key as an environment variable. If you do not have one, contact an account representative.
export LICENSE_KEY=<license-key>Deploy the Kubernetes Gateway API CRDs.
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yamlDeploy the Solo Enterprise for kgateway CRDs by using Helm. The following command uses versions 2.3.5.
helm upgrade -i enterprise-kgateway-crds oci://us-docker.pkg.dev/solo-public/enterprise-kgateway/charts/enterprise-kgateway-crds \ --create-namespace \ --namespace kgateway-system \ --version 2.3.5Note
If you already installed the external auth, rate limit, and Enterprise listener set CRDs, such as by previously installing another Solo product in the same cluster, include the
--set installExtAuthCRDs=falseand--set installRateLimitCRDs=falseflags in the Helm installation.Install Solo Enterprise for kgateway by using Helm.
helm upgrade -i enterprise-kgateway oci://us-docker.pkg.dev/solo-public/enterprise-kgateway/charts/enterprise-kgateway \ -n kgateway-system \ --version 2.3.5 \ --set-string licensing.licenseKey=$LICENSE_KEYMake sure that the
enterprise-kgatewaycontrol plane is running.kubectl get pods -n kgateway-systemExample output:
NAME READY STATUS RESTARTS AGE enterprise-kgateway-5495d98459-46dpk 1/1 Running 0 19s
Annotate the gateway proxy service account
Create a GatewayParameters resource to specify the
eks.amazonaws.com/role-arnIRSA 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} EOFCreate the following
httpGateway resource, which includes a reference to thehttp-lambdaGatewayParameters.kubectl apply -f- <<EOF kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: http namespace: kgateway-system annotations: spec: gatewayClassName: enterprise-kgateway infrastructure: parametersRef: name: http-lambda group: gateway.kgateway.dev kind: GatewayParameters listeners: - protocol: HTTP port: 8080 name: http allowedRoutes: namespaces: from: All EOFCheck the status of the gateway to make sure that your configuration is accepted. Note that in the output, a
NoConflictsstatus ofFalseindicates that the gateway is accepted and does not conflict with other gateway configuration.kubectl get gateway http -n kgateway-system -o yamlVerify that the
httpservice account has theeks.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 Solo Enterprise for kgateway routing.
Log in to the AWS console and navigate to the Lambda page.
Click the Create Function button.
Name the function
echoand click Create function.Replace the default contents of
index.mjswith 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; };Click Deploy.
Set up routing to your function
Create Backend and HTTPRoute resources to route requests to the Lambda function.
Create a Backend resource that references the AWS region, ID of the account that contains the IAM role, and
echofunction that you created.The Backend uses the proxy’s ambient IRSA credentials directly. No
authfield 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 EOFThe Backend instructs the proxy to assume
${INVOKE_ROLE_ARN}before signing Lambda requests.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}" auth: type: AssumeRole assumeRole: roleArn: "${INVOKE_ROLE_ARN}" lambda: functionName: echo EOFCreate an HTTPRoute resource that references the
lambdaBackend.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 EOFGet 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_ADDRESSkubectl port-forward deployment/http -n kgateway-system 8080:8080Confirm that Solo Enterprise for kgateway correctly routes requests to Lambda by sending a curl request to the
echofunction. 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 POSTcurl -H "Host: lambda.${AWS_LAMBDA_REGION}.amazonaws.com" \ $INGRESS_GW_ADDRESS:8080/echo \ -d '{"key1":"value1", "key2":"value2"}' -X POSTExample response:
{"statusCode":200,"body":"Response from AWS Lambda. Here's the request you just sent me: {\"key1\":\"value1\",\"key2\":\"value2\"}"}%
At this point, Solo Enterprise for 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
Delete the
lambdaHTTPRoute andlambdaBackend.kubectl delete HTTPRoute lambda -n kgateway-system kubectl delete Backend lambda -n kgateway-systemUse the AWS Lambda console to delete the
echotest function.
IRSA authorization (optional)
If you no longer need to access Lambda functions from Solo Enterprise for kgateway:
Delete the GatewayParameters resources.
kubectl delete GatewayParameters http-lambda -n kgateway-systemRemove the reference to the
http-lambdaGatewayParameters from thehttpGateway.kubectl apply -f- <<EOF kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: http namespace: kgateway-system spec: gatewayClassName: enterprise-kgateway listeners: - protocol: HTTP port: 8080 name: http allowedRoutes: namespaces: from: All EOFDelete the pod identity webhook.
kubectl delete deploy pod-identity-webhookRemove cert-manager.
kubectl delete -f cert-manager.yaml -n cert-manager kubectl delete ns cert-managerDelete 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-policyDelete the AWS IAM resources from the Lambda account.
aws iam detach-role-policy --role-name lambda-invoke-role --policy-arn=arn:aws:iam::${LAMBDA_ACCOUNT_ID}:policy/kgateway-lambda-invoke-policy aws iam delete-role --role-name lambda-invoke-role aws iam delete-policy --policy-arn=arn:aws:iam::${LAMBDA_ACCOUNT_ID}:policy/kgateway-lambda-invoke-policyDelete the AWS IAM resources from the authentication account.
aws iam delete-role-policy --role-name kgateway-proxy-role --policy-name allow-assume-lambda-role aws iam delete-role --role-name kgateway-proxy-role