Istio Egress to DynamoDB

Took a while to figure out how to properly configure Istio egress to allow a service to talk to DynamoDB. I didn’t find many up-to-date resources out there on the topic, so decided to share what worked for me.

Word of caution: Istio is a young project and changing very rapidly. This post is based on this networking API version: networking.istio.io/v1alpha3

This post assumes that you are already running a service in Kubernetes and Istio. The service now needs to talk to DynamoDB. The DynamoDB table should exist and your Kubernetes cluster nodes should have proper IAM role(s) to talk to your DynamoDB table. By default, Istio prevents any connections outside of the mesh unless it is explicitly allowed. The recommended way to do this is with a ServiceEntry, but you can do it by IP range too.

Before starting anything, I really recommend running through the Egress Task. It’s fast, helps to familiarize yourself with the features and helps to verify that you can indeed get it working.

The primary thing that tripped me up when I was trying this for the first time was what that you cannot use a wildcard in your hosts for exposing HTTPS services via a ServiceEntry. EG: you cannot make a single ServiceEntry with the host *.amazonaws.com to give access to most all of the AWS services. This is mentioned in the Istio docs here. You can use a wildcard in your HTTP hosts.

AWS session in the service

To connect to DynamoDB, our AWS session looks like this (written in Go):

sess, err := session.NewSession(&aws.Config{
    Region:                        aws.String(endpoints.UsEast1RegionID),
    CredentialsChainVerboseErrors: aws.Bool(true),
    LogLevel:                      aws.LogLevel(aws.LogDebugWithHTTPBody),
})

if err != nil {
    return errors.New(fmt.Sprintf("Failed to create AWS session with error %s", err.Error()))
}

// Continue with your code to interact with DynamoDB

So, nothing fancy here, but let’s point out a couple of things:

  • Not specifying credentials, which means the SDK will basically fall back to IAM roles. This is what we will be using.
  • Besides region, the other parameters are very helpful for debugging outbound connections. Just look at the logs on your pod for failed requests.

At this point, go ahead and deploy your service and see the logs after you try to interact with DynamoDB. Should see some errors about which requests were tried and their errors. It’s good to note the hosts here.

In order to allow the service to interact with DynamoDB we need to expose the metadata server, IAM Service and DynamoDB.

Egress to metadata server

Since we are using IAM to authenticate, the AWS SDK will send a request to 169.254.169.254 which is the metadata server. Envoy will block this, we unblock it with some good old YAML:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: aws-metadata-service-entry
spec:
  hosts:
  - 169.254.169.254
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  location: MESH_EXTERNAL

Egress to IAM service

Again, since we are using IAM for authentication, the AWS SDK will also send a request to sts.amazonaws.com which is the IAM Service. Let’s allow this request too. Note, this time it is HTTPS so we also need a VirtualService:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: aws-sts-service-entry
spec:
  hosts:
  - sts.amazonaws.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aws-sts-virtual-service
spec:
  hosts:
  - sts.amazonaws.com
  tls:
  - match:
    - port: 443
      sni_hosts:
      - sts.amazonaws.com
    route:
    - destination:
        host: sts.amazonaws.com
        port:
          number: 443
      weight: 100

Egress to DynamoDB

Finally, what we actually want to do, interact with DynamoDB. Allow this request with the following (modify AWS region as necessary):

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: dynamodb-service-entry
spec:
  hosts:
  - dynamodb.us-east-1.amazonaws.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aws-dynamodb-virtual-service
spec:
  hosts:
  - dynamodb.us-east-1.amazonaws.com
  tls:
  - match:
    - port: 443
      sni_hosts:
      - dynamodb.us-east-1.amazonaws.com
    route:
    - destination:
        host: dynamodb.us-east-1.amazonaws.com
        port:
          number: 443
      weight: 100

Conclusion

After those definitions are deployed to your cluster, your service should now be allowed to talk to the necessary servers in order to authenticate using IAM and to interact with DynamoDB.

Just want to reiterate: no wildcard in your HTTPS hosts for egress. Istio is still a young project, so this might change down the road.