Search code examples
amazon-web-servicesasp.net-coreaws-api-gatewayamazon-elbamazon-ecs

AWS API Gateway to .NET Core Web Api running in ECS


EDIT

I now realise that I need to install a certificate on the server and validate the client certificate separately. I'm looking at https://github.com/xavierjohn/ClientCertificateMiddleware

I believe the certificate has to be from one of the CA's listed in AWS doco - http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-supported-certificate-authorities-for-http-endpoints.html

This certificate allows API Gateway to establish a HTTPS connection to the instance and it passes along the client certificate that can be validated.

ORIGINAL POST

I am trying to configure a new microservices environment and I'm having a few issues.

Here is what I'm trying to achieve:

  • Angular website connects to backend API via API Gateway (URL: gateway.company.com.au)
  • API Gateway is configured with 4 stages - DEV, UAT, PreProd and PROD
  • The resources in API Gateway are a HTTP Proxy to the back-end services via a Network Load Balancer. Each service in each stage will get a different port allocated: i.e. 30,000, 30,001, etc for DEV, 31,000, 31,000, etc for UAT
  • The network load balancer has a DNS of services.company.com.au
  • AWS ECS hosts the docker containers for the back-end services. These services are .NET Core 2.0 Web API projects
  • The ECS task definition specifies the container image to use and has a port mapping configured - Host Port: 0 Container Port: 4430. A host port of 0 is dynamically allocated by ECS.
  • The network load balancer has a listener for each microservice port and forwards the request to a target group. There is a target group for each service for each environment.
  • The target group includes both EC2 instances in the ECS cluster and ports are dynamically assigned by ECS
  • This port is then mapped by ECS/Docker to the container port of 4430

In order to prevent clients from calling services.company.com.au directly, the API Gateway is configured with a Client Certificate.

In my Web API, I'm building the web host as follows:

.UseKestrel(options =>
{
    options.Listen(new IPEndPoint(IPAddress.Any, 4430), listenOptions =>
    {
        const string certBody = "-----BEGIN CERTIFICATE----- Copied from API Gateway Client certificate -----END CERTIFICATE-----";
        var cert = new X509Certificate2(Encoding.UTF8.GetBytes(certBody));

        var httpsConnectionAdapterOptions = new HttpsConnectionAdapterOptions
        {
            ClientCertificateMode = ClientCertificateMode.AllowCertificate,
            SslProtocols = System.Security.Authentication.SslProtocols.Tls,
            ServerCertificate = cert
        };
        listenOptions.UseHttps(httpsConnectionAdapterOptions);
    });
})

My DockerFile is:

FROM microsoft/aspnetcore:2.0
ARG source
WORKDIR /app
EXPOSE 80 443
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "microservice.company.com.au.dll"]

When I use Postman to try and access the service, I get a 504 Gateway timeout. The CloudWatch log shows:

(e4d594b7-c8f3-11e7-8458-ef6f94e65b64) Sending request to http://microservice.company.com.au:30000/service
(e4d594b7-c8f3-11e7-8458-ef6f94e65b64) Execution failed due to an internal error
(e4d594b7-c8f3-11e7-8458-ef6f94e65b64) Method completed with status: 504

I've been able to get the following architecture working:

  • API Gateway
  • Application Load Balancer - path-based routing to direct to the right container
  • ECS managing ports on the load balancer
  • The container listening on HTTP port 80

Unfortunately, this leaves the services open on the DNS of the Application Load Balancer due to API Gateway being able to only access public load balancers.

I'm not sure where it's failing but I suspect I've not configured .NET Core/Kestrel correctly to terminate the SSL using the Client Certificate.

In relation to this overall architecture, it would make things easier if:

  1. The public Application Load Balancer could be used with a HTTPS listener using the Client Certificate of API Gateway to terminate the SSL connection
  2. API Gateway could connect to internal load balancers without using Lambda as a proxy

Any tips or suggestions will be considered but at the moment, the main goal is to get the first architecture working.

I more information is required let me know and I will update the question.


Solution

  • The problem was caused by the security group attached to the EC2 instances that formed the ECS cluster not allowing the correct port range. The security group for each EC2 instance in the cluster needs to allow the ECS dynamic port range.