Get started

Invoke AWS Lambda functions from your Gloo Gateway cluster by using an IAM role for a service account (IRSA).

Amazon Web Services (AWS) offers the ability to associate an IAM role with a Kubernetes service account, also known as creating an IRSA. Gloo Gateway supports discovering and invoking AWS Lambda functions by using an IRSA. For more information, see the AWS documentation.

In this getting started tutorial, you follow these steps:

AWS resources:

Gloo resources:

After you create these resources, requests to your Lambda function follow this network traffic flow:

Figure: Gloo custom resources for AWS Lambda details
  1. A client makes a request to the host and path that you set up for the function, such as https://www.example.com/test-lambda.
  2. Gloo Gateway receives the request for the host as specified in the route table, and matches the host to a particular AWS account and Lambda function as specified in the cloud provider and cloud resource. Using these details, Gloo Gateway assumes an IAM role to invoke the function.
  3. The Lambda function in your AWS account receives the request, and returns a response to Gloo Gateway.
  4. Gloo Gateway applies any transformations that you configured (such as AWS response transformations) to the response, and returns it to the client.

Before you begin

  1. Install Gloo Gateway. Note that certain Lambda integration features, such as unwrapping Lambda responses in the same way as an AWS API Gateway, require ingress gateway proxies to run Istio 1.15.1 or later.

    • Install quickly with meshctl.
    • Customize your installation with Helm.
  2. Configure an HTTPS listener on your ingress gateway.

Configure AWS IAM resources

Save your AWS details, and create an IRSA for the Gloo Gateway deployment pods to use.

  1. Save the details of the AWS region and account that your Lambda functions are in.

    export AWS_REGION=<region>
    export ACCOUNT_ID=<account_id>
    
  2. Save the AWS Security Token Service (AWS STS) endpoint to use when retrieving the necessary AWS credentials for accessing Lambda functions. Note that STS endpoints are unique to a particular listener port on a workload. For more information about STS endpoints, see the AWS documentation.

    • Global STS endpoint (default):
      export STS_ENDPOINT=sts.amazonaws.com
      
    • Regional STS endpoints:
      export STS_ENDPOINT=sts.$AWS_REGION.com
      
  3. Associate an IAM OIDC provider to the EKS cluster that you plan to use for Gloo Gateway.

  4. Save your cluster's OIDC identity provider in an environment variable.

    export OIDC_PROVIDER=$(aws eks describe-cluster --name $CLUSTER_NAME --region $AWS_REGION --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
    
  5. Create an IAM policy to allow access to the following four Lambda actions. Note: In this getting started guide, the permissions to discover and invoke functions are listed in the same policy, and this policy is used by both the Gloo Gateway management server for discovery and the gateway proxy for invocation. 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 gloo-lambda-policy --policy-document file://policy.json 
    
  6. Use an IAM role to associate the policy with the Kubernetes service account for the Gloo management server. The management server assumes this role to discover Lambda functions. For more information about these steps, see the AWS documentation.

    1. Create the following IAM role.
      cat >discover-role.json <<EOF
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
              "StringEquals": {
                "${OIDC_PROVIDER}:aud": "${STS_ENDPOINT}",
                "${OIDC_PROVIDER}:sub": "system:serviceaccount:gloo-mesh:gloo-mesh-mgmt-server"
              }
            }
          }
        ]
      }
      EOF
      
      aws iam create-role --role-name gloo-lambda-mgmt-discover --assume-role-policy-document file://discover-role.json
      
    2. Use the IAM role to associate the IAM policy with the service account. This IAM role for the service account is known as an IRSA.
      aws iam attach-role-policy --role-name gloo-lambda-mgmt-discover --policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/gloo-lambda-policy
      
    3. Verify that the policy is attached to the role.
      aws iam list-attached-role-policies --role-name gloo-lambda-mgmt-discover
      

      Example output:

      {
          "AttachedPolicies": [
              {
                  "PolicyName": "gloo-lambda-policy",
                  "PolicyArn": "arn:aws:iam::111122223333:policy/gloo-lambda-policy"
              }
          ]
      }
      
    4. Annotate the management server service account with the ARN of its IAM role. In the following Helm upgrade command, make sure to include the same Helm values that you specifed when you installed Gloo Gateway, either as a configuration file in the --values flag or with --set flags. Otherwise, any previous custom values that you set might be overwritten, which might mean that your Gloo agent and gateway proxies are removed. Additionally, note that your release might be named gloo-mesh-enterprise instead of gloo-mgmt. For more information, see Get your Helm chart values.
      helm upgrade --install gloo-platform gloo-platform/gloo-platform \
      --namespace gloo-mesh \
      --version $GLOO_VERSION \
      --values gloo-gateway-single.yaml \
      --set common.cluster=$CLUSTER_NAME \
      --set licensing.glooGatewayLicenseKey=$GLOO_GATEWAY_LICENSE_KEY \
      --set glooMgmtServer.serviceAccount.extraAnnotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::$ACCOUNT_ID:role/gloo-lambda-mgmt-discover
      
    5. Verify that the service account is annotated with the IRSA.
      kubectl describe serviceaccount gloo-mesh-mgmt-server -n gloo-mesh
      

      Example output:

      Name:                gloo-mesh-mgmt-server
      Namespace:           gloo-mesh
      Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/gloo-lambda-mgmt-discover
      Image pull secrets:  <none>
      Mountable secrets:   gloo-mesh-mgmt-server-token-qqjfl
      Tokens:              gloo-mesh-mgmt-server-token-qqjfl
      ...
      
  7. Use an IAM role to associate the policy with the Kubernetes service account for the ingress gateway. The gateway assumes this role to invoke Lambda functions. For more information about these steps, see the AWS documentation.

    1. Find the name of the service account for the ingress gateway. The service account might exist in another namespace, depending on where you deployed your gateway proxy.
      kubectl get serviceaccount -n gloo-mesh-gateways
      

      In this example output, istio-ingressgateway-1-20-service-account is the name of the ingress gateway service account:

      NAME                                        SECRETS   AGE
      default                                     1         45m
      istio-ingressgateway-1-20-service-account   1         45m
      
    2. Create the following IAM role. Change the namespace and name of the ingress gateway service account as needed.
      cat >invoke-role.json <<EOF
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
              "StringEquals": {
                "${OIDC_PROVIDER}:aud": "${STS_ENDPOINT}",
                "${OIDC_PROVIDER}:sub": "system:serviceaccount:gloo-mesh-gateways:istio-ingressgateway-1-20-service-account"
              }
            }
          }
        ]
      }
      EOF
            
      aws iam create-role --role-name gloo-lambda-gateway-invoke --assume-role-policy-document file://invoke-role.json
      
    3. Use the IAM role to associate the IAM policy with the service account. This IAM role for the service account is known as an IRSA.
      aws iam attach-role-policy --role-name gloo-lambda-gateway-invoke --policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/gloo-lambda-policy
      
    4. Verify that the policy is attached to the role.
      aws iam list-attached-role-policies --role-name gloo-lambda-gateway-invoke
      

      Example output:

      {
          "AttachedPolicies": [
              {
                  "PolicyName": "gloo-lambda-policy",
                  "PolicyArn": "arn:aws:iam::111122223333:policy/gloo-lambda-policy"
              }
          ]
      }
      
    5. Annotate the ingress gateway service account with the ARN of its IAM role. These steps differ depending on whether you installed the ingress gateway with the istioInstallations Helm chart setting, created a GatewayLifecycleManager custom resource, or manually deployed an unmanaged ingress gateway with an Istio Helm chart.

      If you installed managed gateway proxies by using the istioInstallations Helm chart setting:

      1. Perform a canary upgrade of your gateway proxy. When you update your values file to add a canary entry to the istioInstallations.northSouthGateways.installations list, include the following following section. Replace $ACCOUNT_ID with your actual account ID, and update the name of the ingress gateway service account as needed. Note that the other environment variables are provided as example placeholders for the actual values in your file.
        istioInstallations:
           ...
           northSouthGateways:
               - enabled: true
                 name: istio-ingressgateway
                 installations:
                   # Installation entry for the canary revision
                   - gatewayRevision: $REVISION
                     clusters:
                       - name: $CLUSTER_NAME
                         activeGateway: false
                     istioOperatorSpec:
                       profile: empty
                       hub: $REPO
                       tag: $ISTIO_IMAGE
                       namespace: gloo-mesh-gateways
                       # NEW SECTION
                       k8s: 
                         overlays:
                           - apiVersion: v1
                             kind: ServiceAccount
                             name: istio-ingressgateway-1-20-service-account
                             patches:
                               - path: metadata.annotations.eks\.amazonaws\.com/role-arn
                                 value:
                                   arn:aws:iam::$ACCOUNT_ID:role/gloo-lambda-gateway-invoke
        
      2. When you follow the other steps in the upgrade guide, be sure to also include the annotation that you set for the management server in prior steps, so that the value is not overwritten.
        helm upgrade --install gloo-platform gloo-platform/gloo-platform \
        --namespace gloo-mesh \
        --version $GLOO_VERSION \
        --values gloo-gateway-single.yaml \
        --set common.cluster=$CLUSTER_NAME \
        --set licensing.glooGatewayLicenseKey=$GLOO_GATEWAY_LICENSE_KEY \
        --set glooMgmtServer.serviceAccount.extraAnnotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::$ACCOUNT_ID:role/gloo-lambda-mgmt-discover
        

      If you installed managed gateway proxies by creating a GatewayLifecycleManager CR, perform a canary upgrade to annotate the ingress gateway service account. For more information about these steps, see Performing a canary upgrade.

      1. Edit the GatewayLifecycleManager resource for the gateway that you deployed to add another installation entry for the canary revision. For the canary revision, be sure to set defaultRevision to false so that only the existing revision continues to run.
        kubectl edit GatewayLifecycleManager istio-ingressgateway -n gloo-mesh
        

        For example, you might add the following $REVISION-lambda canary revision as a new entry in the installations section. Replace $ACCOUNT_ID with your actual account ID, and update the name of the ingress gateway service account as needed. Note that the other environment variables are provided as example placeholders for the actual values in your file.

        apiVersion: admin.gloo.solo.io/v2
        kind: GatewayLifecycleManager
        metadata:
          name: istio-ingressgateway
          namespace: gloo-mesh
        spec:
          installations:
            # Existing revision
            - gatewayRevision: $REVISION
              clusters:
              - name: $CLUSTER_NAME
                # Keep this field set to TRUE so that only the existing revision continues to run
                activeGateway: true
              istioOperatorSpec:
                profile: empty
                ...
            # Canary revision
            - gatewayRevision: $REVISION-lambda
              clusters:
              - name: $CLUSTER_NAME
                # Set this field to FALSE so that only the existing revision continues to run
                activeGateway: false
              istioOperatorSpec:
                profile: empty
                hub: $REPO
                tag: $ISTIO_IMAGE
                components:
                  ingressGateways:
                    - name: istio-ingressgateway
                      namespace: gloo-mesh-gateways
                      enabled: true
                      label:
                        istio: ingressgateway
                        app: istio-ingressgateway
                      k8s:
                        service:
                          type: LoadBalancer
                          selector:
                            istio: ingressgateway
                          ports:
                            - name: status-port
                              port: 15021
                              targetPort: 15021
                            - port: 80
                              targetPort: 8080
                              name: http2
                            - port: 443
                              targetPort: 8443
                              name: https
                        overlays:
                          - apiVersion: v1
                            kind: ServiceAccount
                            # Change the name of the ingress gateway service account as needed
                            name: istio-ingressgateway-1-20-service-account
                            patches:
                              - path: metadata.annotations.eks\.amazonaws\.com/role-arn
                                value:
                                  # Replace with your own account ID
                                  arn:aws:iam::$ACCOUNT_ID:role/gloo-lambda-gateway-invoke
        
      2. Verify that the ingress gateway for the canary installation is created.
        kubectl get all -n gloo-mesh-gateways
        
      3. Switch to the new gateway by changing activeGateway to false for the old revision and to true for the new revision.
        kubectl edit GatewayLifecycleManager istio-ingressgateway -n gloo-mesh
        

        Example:

        apiVersion: admin.gloo.solo.io/v2
        kind: GatewayLifecycleManager
        metadata:
          name: istio-ingressgateway
          namespace: gloo-mesh
        spec:
          installations:
            # Old revision
            - gatewayRevision: $REVISION
              clusters:
              - name: $CLUSTER_NAME
                # Set this field to FALSE
                activeGateway: false
              istioOperatorSpec:
                profile: empty
                ...
            # New revision
            - gatewayRevision: $REVISION-lambda
              clusters:
              - name: $CLUSTER_NAME
                # Set this field to TRUE
                activeGateway: true
              istioOperatorSpec:
                profile: empty
                ...
        
      4. Verify that the active gateways for the new revision are created, which do not have the revision appended to the name. Note that gateways for the inactive revision that you previously ran also exist in the namespace, in the case that a rollback is required.
        kubectl get all -n gloo-mesh-gateways
        
      5. To uninstall the previous installation, you can edit the GatewayLifecycleManager resource to remove the old revision's entry from the installations list.
        kubectl edit GatewayLifecycleManager istio-ingressgateway -n gloo-mesh
        

      If you manually deployed unmanaged Istio ingress gateways, patch the deployment with the anotated service account.

      These steps use the post rendering feature supported in Helm 3.1 and later, along with Kustomize. These features patch the rendered manifest of the istio-ingressgateway deployment before it is applied to the cluster without the need to modify the Helm chart itself, because deployment patches cannot be added to the istio-ingressgateway Helm chart directly.

      1. Save the following patch, which updates the ingress gateway deployment with the annotated service account before the deployment is applied to the cluster.

        cat > sa-patch.yaml <<EOF
        apiVersion: v1
        kind: ServiceAccount
        metadata:
          # Change the name of the ingress gateway service account as needed
          name: istio-ingressgateway-1-20-service-account
          annotations:
            eks.amazonaws.com/role-arn: "arn:aws:iam::$ACCOUNT_ID:role/gloo-lambda-gateway-invoke"
        EOF
        
      2. To use Kustomize files with Helm rendering, which requires stdin/stdout, create a shell script named kustomize.sh.

        cat > kustomize.sh <<EOF
        #!/bin/sh
        cat > base.yaml
        exec kubectl kustomize
        EOF
        chmod +x ./kustomize.sh
        
      3. Create the kustomization.yaml file, which provides the patch input for Kustomize.

        cat > kustomization.yaml <<EOF
        resources:
        - base.yaml
        patchesStrategicMerge:
        - sa-patch.yaml
        EOF
        
      4. Follow the guide to upgrade the ingress gateway. When you run the helm upgrade command for the ingress gateway, be sure to include the --post-renderer ./kustomize.sh flag, such as the following:

        helm upgrade --install istio-ingressgateway-${REVISION} istio/gateway \
          --version ${ISTIO_IMAGE} \
          --create-namespace \
          --namespace gloo-mesh-gateways \
          --post-renderer ./kustomize.sh \
          --wait \
          -f ingress-gateway-values.yaml
        
    6. Verify that the service account is annotated with the IRSA.
      kubectl describe serviceaccount istio-ingressgateway-1-20-service-account -n gloo-mesh-gateways
      

      Example output:

      Name:                istio-ingressgateway-1-20-service-account
      Namespace:           gloo-mesh-gateways
      Labels:              app=istio-ingressgateway
                           install.operator.istio.io/owning-resource=istio-ingressgateway-1-20
                           install.operator.istio.io/owning-resource-namespace=gm-iop-1-20
                           istio=ingressgateway
                           istio.io/rev=1-20
                           operator.istio.io/component=IngressGateways
                           operator.istio.io/managed=Reconcile
                           operator.istio.io/version=1.20.2-solo
                           release=istio
                           revision=1-20
      Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::931713665590:role/gloo-lambda-gateway-invoke
      Image pull secrets:  <none>
      Mountable secrets:   istio-ingressgateway-1-20-service-account-token-rwvq8
      Tokens:              istio-ingressgateway-1-20-service-account-token-rwvq8
      Events:              <none>
      

In this getting started guide, the IRSA for the management server is used for all function discovery, and the IRSA for the gateway is used for all function invocation. In a more advanced or multitenant setup, you might create override IAM roles to use for discovering and invoking Lambda functions instead of the IRSAs you annotate the service accounts with. For more information, see Roles for invocation and discovery.

Create a Lambda function for testing

Create an AWS Lambda function to test Gloo Gateway routing.

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

  2. Click the Create Function button.

  3. Name the function test-lambda 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

To invoke the function from Gloo Gateway, provide your AWS account and Lambda details in the CloudProvider and CloudResources resources. Then, set up routing to your function by creating a RouteTable.

Figure: Gloo custom resources for AWS Lambda details
  1. Define your AWS details and IAM roles in a CloudProvider resource. The configuration steps vary depending on whether you want Gloo Gateway to automatically discover the Lambda functions in your account and region, or you want to manually list functions in a CloudResources resource.

    In multicluster setups, you must create CloudProvider and any CloudResources resources in the gloo-mesh namespace of the management cluster.
    1. Define your AWS details in a CloudProvider resource. These settings enable automatic discovery of functions in your account and region, but filters the functions for the name test-lambda.
      kubectl apply -f - <<EOF
      apiVersion: infrastructure.gloo.solo.io/v2
      kind: CloudProvider
      metadata:
        name: aws-provider
        namespace: gloo-mesh
      spec:
        aws:
          accountId: "$ACCOUNT_ID"
          region: $AWS_REGION
          stsEndpoint: $STS_ENDPOINT
          lambda:
            discovery:
              enabled: true
              filter:
                names: test-lambda
                latestOnly: true
            invokeRoleName: gloo-lambda-gateway-invoke
      EOF
      
    2. Verify that Gloo Gateway discovered the test-lambda function. Gloo automatically creates a CloudResources configuration that contains entries for each Lambda that it discovers.
      kubectl get CloudResources -n gloo-mesh
      
    1. Define your AWS details in a CloudProvider resource.
      kubectl apply -f - <<EOF
      apiVersion: infrastructure.gloo.solo.io/v2
      kind: CloudProvider
      metadata:
        name: aws-provider
        namespace: gloo-mesh
      spec:
        aws:
          accountId: "$ACCOUNT_ID"
          region: $AWS_REGION
          stsEndpoint: $STS_ENDPOINT
          lambda:
            invokeRoleName: gloo-lambda-gateway-invoke
      EOF
      
    2. Specify the test Lambda that you created in a CloudResources resource.
      kubectl apply -f - <<EOF
      apiVersion: infrastructure.gloo.solo.io/v2
      kind: CloudResources
      metadata:
        name: aws-functions
        namespace: gloo-mesh
      spec:
        # Name of the CloudProvider resource
        provider: aws-provider
        aws: 
          lambda:
              # Actual name of the function in AWS
            - lambdaFunctionName: test-lambda
              # Version of the function to call
              qualifier: $LATEST
      EOF
      

  2. Create a RouteTable resource to direct all requests on the /test-lambda path to your Lambda function. Update the example values with your own details as needed, such as the virtualGateways reference details.

    kubectl apply -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: test-lambda-route
      namespace: gloo-mesh
    spec:
      # Applies to any host; can indicate a specific domain, like example.com
      hosts:
        - '*'
      # Selects a virtual gateway you previously created.
      # Change name and namespace as needed.
      virtualGateways:
        - name: istio-ingressgateway
          namespace: bookinfo
      http:
        - name: test-lambda-route
          labels:
            route: lambda
          matchers:
          - uri:
              prefix: /test-lambda
          forwardTo:
            destinations:
              # Reference to the function in the CloudProvider resource
              - awsLambda:
                  cloudProvider:
                    name: aws-provider
                    namespace: gloo-mesh
                    cluster: $CLUSTER_NAME
                  function: test-lambda
    EOF
    
  3. Get the hostname of your ingress gateway to test the /test-lambda route.

    export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    echo $INGRESS_GW_IP
    
  4. Send a request to the Lambda endpoint to verify that the request is successfully resolved by the gateway.

    curl -vik https://${INGRESS_GW_IP}:443/test-lambda -H "host: www.example.com:443"
    

    Example output:

    Response from AWS Lambda. Here's the request you just sent me: {"headers":{":authority":"www.example.com",":method":"GET",":path":"/test-lambda",":scheme":"http","accept":"*/*","user-agent":"curl/7.79.1","x-envoy-decorator-operation":"dummy-route-o4bo-WppHSxD6Ox2.badHost.solo.io:8080/test-lambda*","x-envoy-internal":"true","x-envoy-peer-metadata":"ChQKDk<...>","x-envoy-peer-metadata-id":"router~192.168.47.140~istio-ingressgateway-1-20-68bdd78cc4-zqjx7.gloo-mesh-gateways~gloo-mesh-gateways.svc.cluster.local","x-forwarded-for":"192.168.90.112","x-forwarded-proto":"http","x-request-id":"40e70781-3da4-4cf1-8fd2-47b84858fffb"},"httpMethod":"GET","path":"/test-lambda","queryString":""}% 
    

    Note: Gloo Gateway uses a dummy route for the connection between Gloo Gateway and AWS Lambda, such as dummy-route-o4bo-WppHSxD6Ox2.badHost.solo.io:8080/test-lambda* in this example output. This route indicates that the connection is functioning as intended.

Next steps

Now that you've set up Gloo Gateway to invoke Lambda functions, check out the following pages to configure your own functions for Gloo Gateway invocation.