Manage multitenancy

As you develop your Lambda strategy, you might want to adjust permissions to determine which teams in your organization can access which Lambda functions in your AWS accounts. By using Gloo multitenancy resources and AWS IAM permissions, you can control which workloads in your Gloo Gateway environment can discover and invoke specific Lambda functions.

In multicluster setups, you must create CloudProvider and any CloudResources resources in the gloo-mesh namespace of the management cluster.

Use CloudProvider CRs for multitenancy

Use Gloo custom resources, such as workspaces and cloud providers, to separate Lambda invocation access by team.

For example, consider Team A and Team B. Both teams have Lambda functions that are deployed to an AWS account. You want to ensure that Team A can only access its functions, and Team B can only access its functions. The following diagram shows the separation of resources according to each team.

Figure: AWS Lambda resources and Gloo custom resources for Team A and Team B multitenancy

To manage your teams’ access, you create the following resources.

Each workspace includes only the namespace for each team (team-a or team-b) in any workload cluster in your Gloo Gateway setup. All of the Gloo resources for Lambda are created in these namespaces.

Additionally, an ops workspace contains the resources that configure gateway settings, such as the VirtualGateway. The workspace settings ensure that the resources from each teams’ workspaces are exported to the ops namespace, so that Gloo Gateway can access the CloudResources destinations that represent Lambda functions.

Team A:

apiVersion: admin.gloo.solo.io/v2
kind: Workspace
metadata:
  name: team-a
  namespace: gloo-mesh
spec:
  workloadClusters:
    - name: '*'
      namespaces:
        - name: 'team-a'
---
apiVersion: admin.gloo.solo.io/v2
kind: WorkspaceSettings
metadata:
  name: team-a
  namespace: team-a
spec:
  exportTo:
  - workspaces:
    - name: ops
  options:
    serviceIsolation:
      enabled: true

Team B:

apiVersion: admin.gloo.solo.io/v2
kind: Workspace
metadata:
  name: team-b
  namespace: gloo-mesh
spec:
  workloadClusters:
    - name: '*'
      namespaces:
        - name: 'team-b'
---
apiVersion: admin.gloo.solo.io/v2
kind: WorkspaceSettings
metadata:
  name: team-b
  namespace: team-b
spec:
  exportTo:
  - workspaces:
    - name: ops
  options:
    serviceIsolation:
      enabled: true

Operations (gateway):

apiVersion: admin.gloo.solo.io/v2
kind: Workspace
metadata:
  name: ops
  namespace: gloo-mesh-gateways
spec:
  workloadClusters:
    - name: '*'
      namespaces:
        - name: 'gloo-mesh-gateways'
---
apiVersion: admin.gloo.solo.io/v2
kind: WorkspaceSettings
metadata:
  name: ops
  namespace: gloo-mesh-gateways
spec:
  importFrom:
  - workspaces:
    - name: team-a
    - name: team-b
  options:
    serviceIsolation:
      enabled: true

Each CloudProvider specifies each team's individual IAM role for Lambda invocation. For example, say that the invoke-team-a IAM role allows access only to Team A's Lambda functions. Any workloads in Team A's workspace that attempt to invoke functions through Gloo Gateway must use this invoke-team-a IAM role.

Team A:

apiVersion: infrastructure.gloo.solo.io/v2
kind: CloudProvider
metadata:
  name: team-a-111122223333-us-west-2
  namespace: team-a
spec:
  aws:
    accountId: "111122223333"
    region: us-west-2
    stsEndpoint: sts.amazonaws.com
    lambda:
      # Role ARN is arn:aws:iam::111122223333:role/invoke-team-a
      invokeRoleName: invoke-team-a

Team B:

apiVersion: infrastructure.gloo.solo.io/v2
kind: CloudProvider
metadata:
  name: team-b-111122223333-us-west-2
  namespace: team-b
spec:
  aws:
    accountId: "111122223333"
    region: us-west-2
    stsEndpoint: sts.amazonaws.com
    lambda:
      # Role ARN is arn:aws:iam::111122223333:role/invoke-team-b
      invokeRoleName: invoke-team-b

Each CloudResources resource specifies the functions that each team can invoke. For example, Team A can invoke only the team-a-lambda-1 and team-a-lambda-2 functions.

Team A:

apiVersion: infrastructure.gloo.solo.io/v2
kind: CloudResources
metadata:
  name: team-a-111122223333-us-west-2
  namespace: team-a
spec:
  provider: team-a-111122223333-us-west-2
  aws:
    lambda:
      # Function ARN is arn:aws:lambda:us-west-2:111122223333:function:team-a-lambda-1:$LATEST
      - lambdaFunctionName: team-a-lambda-1-latest
        qualifier: $LATEST
      # Function ARN is arn:aws:lambda:us-west-2:111122223333:function:team-a-lambda-2:$LATEST
      - lambdaFunctionName: team-a-lambda-2-latest
        qualifier: $LATEST

Team B:

apiVersion: infrastructure.gloo.solo.io/v2
kind: CloudResources
metadata:
  name: team-b-111122223333-us-west-2
  namespace: team-b
spec:
  provider: team-b-111122223333-us-west-2
  aws:
    lambda:
      # Function ARN is  arn:aws:lambda:us-west-2:111122223333:function:team-b-lambda-1:$LATEST
      - lambdaFunctionName: team-b-lambda-1-latest
        qualifier: $LATEST
      # Function ARN is  arn:aws:lambda:us-west-2:111122223333:function:team-b-lambda-2:$LATEST
      - lambdaFunctionName: team-b-lambda-2-latest
        qualifier: $LATEST

In each route table, you create routes for each function that the team has access to. The destinations reference the CloudProvider and CloudResources details that you previously defined.

Team A:

apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: team-a-lambda-routes
  namespace: team-a
spec:
  hosts:
    - 'team-a.foo.com'
  virtualGateways:
    - name: istio-ingressgateway
      namespace: gloo-mesh-gateways
  http:
    - name: team-a-lambda-1-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /a-lambda-1
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-a-111122223333-us-west-2
              namespace: team-a
              cluster: $CLUSTER_NAME
            function: team-a-lambda-1-latest
    - name: team-a-lambda-2-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /a-lambda-2
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-a-111122223333-us-west-2
              namespace: team-a
              cluster: $CLUSTER_NAME
            function: team-a-lambda-2-latest

Team B:

apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: team-b-lambda-routes
  namespace: team-b
spec:
  hosts:
    - 'team-b.foo.com'
  virtualGateways:
    - name: istio-ingressgateway
      namespace: gloo-mesh-gateways
  http:
    - name: team-b-lambda-1-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /b-lambda-1
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-b-111122223333-us-west-2
              namespace: team-b
              cluster: $CLUSTER_NAME
            function: team-b-lambda-1-latest
    - name: team-b-lambda-2-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /b-lambda-2
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-b-111122223333-us-west-2
              namespace: team-b
              cluster: $CLUSTER_NAME
            function: team-b-lambda-2-latest

This example VirtualGateway resource exists in the ops workspace. The gateway listens only for requests to routes that are defined by route tables that list *.foo.com as the host. Within these route tables, the gateway only routes requests to Lambda functions in the 111122223333 account in the us-west-2 region. These filters include all of the routes for both Team A and Team B. Note that if you want the gateway to only route requests to Team A functions, you could specify the iamRoles section. This filter ensures that the gateway can only assume the dev-team-A-* IAM role for invocation, which grants access to only Team A functions.

Operations (gateway):

apiVersion: networking.gloo.solo.io/v2
kind: VirtualGateway
metadata:
  name: istio-ingressgateway
  namespace: gloo-mesh-gateways
spec:
  listeners:
  - http: {}
    port:
      number: 80
  workloads:
  - selector:
      labels:
        istio: ingressgateway
  listeners:
    - port:
        number: 80
      allowedRouteTables:
        - host: '*.foo.com'
          allowedRoutes:
          - cloudProvider:
              aws:
                accountIds:
                  - '111122223333'
                regions:
                  - us-west-2
                #iamRoles:
                #  - dev-team-A-.*

Importing and exporting across workspaces

You can also import and export CloudProviders to other workspaces, so that other teams can invoke the Lambda functions specified by that CloudProvider. When you import a CloudProvider, the CloudResources that are attached to the provider are also implictly imported. To invoke the Lambda functions that these imported CloudResources represent, you can either create a new route table in the second workspace, or import the existing route table from the first workspace.

Keep in mind that when you export a CloudProvider, you give the importing team the permissions to invoke functions associated with the IAM role defined in the CloudProvider. For example, if Team B needs to access lambda-team-a, you can import the CloudProvider from workspace A into workspace B. If the CloudProvider defines invoke-team-a as the invocation role, Team B now has the permissions granted by the role to invoke Team A's functions.

For example, consider Team A and Team B. Team A has Lambda functions that are deployed to an AWS account, and you want to ensure that both Team A and Team B can access Team A's functions. The following diagram shows the separation of resources according to each team.

Figure: AWS Lambda resources and Gloo custom resources for Team A and Team B access to Team A functions

To manage your teams’ access, you create the following resources.

Each workspace includes only the namespace for each team (team-a or team-b) in any workload cluster in your Gloo Gateway setup. All of the Gloo resources for Lambda are created in these namespaces.

The workspace settings for team-a exports the CloudProvider and RouteTable resources from the team-a namespace to the team-b workspace. The workspace settings for team-b imports these resources. Note that the CloudResources that are attached to the provider are also implictly imported.

Team A:

apiVersion: admin.gloo.solo.io/v2
kind: Workspace
metadata:
  name: team-a
  namespace: gloo-mesh
spec:
  workloadClusters:
    - name: '*'
      namespaces:
        - name: 'team-a'
---
apiVersion: admin.gloo.solo.io/v2
kind: WorkspaceSettings
metadata:
  name: team-a
  namespace: team-a
spec:
  exportTo:
  - workspaces:
    - name: team-b
    resources:
    - kind: CLOUD_PROVIDER
      namespace: team-a
    - kind: ROUTE_TABLE
      namespace: team-a
  options:
    serviceIsolation:
      enabled: true

Team B:

apiVersion: admin.gloo.solo.io/v2
kind: Workspace
metadata:
  name: team-b
  namespace: gloo-mesh
spec:
  workloadClusters:
    - name: '*'
      namespaces:
        - name: 'team-b'
---
apiVersion: admin.gloo.solo.io/v2
kind: WorkspaceSettings
metadata:
  name: team-b
  namespace: team-b
spec:
  importFrom:
  - workspaces:
    - name: team-a
  options:
    serviceIsolation:
      enabled: true

The CloudProvider in the Team A workspace, which is exported to the Team B workspace, specifies the invoke-all-teams IAM role, which allows both Team A and Team B the permissions to invoke Team A's Lambda functions. Any workloads in Team A and Team B's workspaces that attempt to invoke functions through Gloo Gateway must use this IAM role.

Team A:

apiVersion: infrastructure.gloo.solo.io/v2
kind: CloudProvider
metadata:
  name: team-a-111122223333-us-west-2
  namespace: team-a
spec:
  aws:
    accountId: "111122223333"
    region: us-west-2
    stsEndpoint: sts.amazonaws.com
    lambda:
      # Role ARN is arn:aws:iam::111122223333:role/invoke-all-teams
      invokeRoleName: invoke-all-teams

Note: This example setup assumes that Team B has no Lambda functions that they must invoke. If Team B does need to invoke their own functions as well as Team A's functions, you might create another CloudProvider in the team-b workspace for their Lambda information too.

The CloudResources specifies Team A's functions. These functions are implicitly exported to the team-b workspace, along with the CloudProvider.

Team A:

apiVersion: infrastructure.gloo.solo.io/v2
kind: CloudResources
metadata:
  name: team-a-111122223333-us-west-2
  namespace: team-a
spec:
  provider: team-a-111122223333-us-west-2
  aws:
    lambda:
      # Function ARN is arn:aws:lambda:us-west-2:111122223333:function:team-a-lambda-1:$LATEST
      - lambdaFunctionName: team-a-lambda-1-latest
        qualifier: $LATEST
      # Function ARN is arn:aws:lambda:us-west-2:111122223333:function:team-a-lambda-2:$LATEST
      - lambdaFunctionName: team-a-lambda-2-latest
        qualifier: $LATEST

Note: This example setup assumes that Team B has no Lambda functions that they must invoke. If Team B does need to invoke their own functions as well as Team A's functions, you might create another CloudResources in the team-b workspace for their function information too.

Create routes in workspace team-a for each Team A function. The destinations reference the CloudProvider and CloudResources details that you previously defined.

Team A:

apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: team-a-lambda-routes
  namespace: team-a
spec:
  hosts:
    - 'foo.com'
  virtualGateways:
    - name: istio-ingressgateway
      namespace: team-b
  http:
    - name: team-a-lambda-1-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /a-lambda-1
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-a-111122223333-us-west-2
              namespace: team-a
              cluster: $CLUSTER_NAME
            function: team-a-lambda-1-latest
    - name: team-a-lambda-2-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /a-lambda-2
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-a-111122223333-us-west-2
              namespace: team-a
              cluster: $CLUSTER_NAME
            function: team-a-lambda-2-latest

If Team B has workloads in their workspace that need to invoke Team A's functions, you can create routes in workspace team-b that invoke the imported Team A functions. The destinations reference the CloudProvider and CloudResources details that you previously defined and imported from workspace team-a.

Team B:

apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: team-b-lambda-routes
  namespace: team-b
spec:
  hosts:
    - 'foo.com'
  virtualGateways:
    - name: istio-ingressgateway
      namespace: team-b
  http:
    - name: team-b-lambda-1-route
      labels:
        route: lambda
      matchers:
      - uri:
          prefix: /b-lambda-1
      forwardTo:
        destinations:
        - awsLambda:
            cloudProvider:
              name: team-b-111122223333-us-west-2
              namespace: team-b
              cluster: $CLUSTER_NAME
            function: team-b-lambda-1-latest

Note: This example setup assumes that Team B has no Lambda functions that they must invoke. If Team B does need to invoke their own functions as well as Team A's functions, you might add more routes to this route table for their functions too.

In this VirtualGateway, the gateway listens only for requests to routes that are defined by route tables that list *.foo.com as the host. Within these route tables, the gateway only routes requests to Lambda functions in the 111122223333 account in the us-west-2 region. These allowedRouteTables filters include all of the routes for Team A. If you created routes for any Team B Lambdas, these matchers include all of the routes for Team B as well.

Note that this virtual gateway is created in the team-b workspace, because that workspace already imports the CloudProvider (and implictly, the CloudResources) that are necessary. If you create the virtual gateway in another workspace, be sure that the workspace imports the resources from the teams’ workspaces to route to their functions.

Team B:

apiVersion: networking.gloo.solo.io/v2
kind: VirtualGateway
metadata:
  name: istio-ingressgateway
  namespace: team-b
spec:
  listeners:
  - http: {}
    port:
      number: 80
  workloads:
  - selector:
      labels:
        istio: ingressgateway
  listeners:
    - port:
        number: 80
      allowedRouteTables:
        - host: '*.foo.com'
          allowedRoutes:
          - cloudProvider:
              aws:
                accountIds:
                  - '111122223333'
                regions:
                  - us-west-2