How can I use an NGINX proxy to access Kibana from outside of a VPC with Amazon Cognito authentication?

Last updated: 2019-07-12

My Amazon Elasticsearch Service cluster is in a virtual private cloud (VPC). I want to use an NGINX proxy to access Kibana from outside the VPC with Amazon Cognito authentication.

Short Description

Use NGINX to configure an Amazon Elastic Compute Cloud (Amazon EC2) instance as a proxy server. The proxy server then forwards browser requests to Amazon Cognito and Kibana.

Note: You can also use an SSH tunnel or Client VPN to access Kibana from outside a VPC with Amazon Cognito authentication. For more information, see How can I access Kibana from outside of a VPC using Amazon Cognito authentication?

Resolution

Important: Your ES domain is more secure when you restrict access to users in the VPC. Before you continue, be sure that this procedure doesn't violate your organization's security requirements.

1.    Create an Amazon Cognito user pool.

2.    Configure a hosted user pool domain.

3.    In the Amazon Cognito console navigation pane, choose Users and groups.

4.    Choose Create user and then complete the fields. Be sure to enter an email address and select the Mark email as verified check box.

5.    Choose the Groups tab and then choose Create group. For Precedence, enter 0. For more information, see Creating a New Group in the AWS Management Console.

6.    Open the Amazon Cognito console again.

7.    Choose Manage Identity Pools, and then choose Create new identity pool.

8.    Enter a name for your identity pool, select the check box to Enable access to unauthenticated identities, and then choose Create Pool.

9.    When you are prompted for access to your AWS resources, choose Allow to create the two default roles associated with your identity pool–one for unauthenticated users and the other for authenticated users.

10.    Configure your Amazon ES domain to use Amazon Cognito authentication for Kibana.
For Cognito User Pool, choose the user pool that you created in step 1.
For Cognito Identity Pool, choose the identity pool that you created in step 8.

11.    Configure your Amazon ES domain to use a resource-based access policy similar to the following. Replace these values:
account-id: your AWS account ID
identity-name: the name of your Amazon Cognito identity pool
ES-name: the name of your Amazon ES domain
region: the Region that your Amazon ES domain is in, such as us-east-1

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::account-id:role/Cognito_identity-nameAuth_Role"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:region:account-id:domain/ES-name/*"
    }
  ]
}

For example, the following access policy uses these values:

AWS account ID: 111122223333
Amazon Cognito identity pool name: MyIdentityPool
Amazon ES domain name: MyES
Region: us-east-1

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/Cognito_MyIdentityPoolAuth_Role"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:us-east-1:111122223333:domain/MyES/*"
    }
  ]
}

12.    Launch an EC2 instance into a public subnet of the same VPC that your Amazon ES domain is in. Be sure that the instance uses the same security group as your Amazon ES domain.

13.    (Optional—you can skip this step if you are using a test environment) Allocate an Elastic IP address and associate it with the instance that you created in the previous step.

14.    (Optional—you can skip this step if you are using a test environment) Configure your DNS to resolve requests to the Elastic IP address. For instructions on how to resolve requests with Amazon Route 53, see Configuring Amazon Route 53 to Route Traffic to an Amazon EC2 Instance.

15.    Connect to the instance and install NGINX.

For instances launched with an Amazon Linux Amazon Machine Image (AMI), use this command:

$ sudo yum install nginx

For instances launched with an Amazon Linux 2 AMI, use this command:

$ sudo amazon-linux-extras install nginx1.12

16.    To configure SSL for NGINX, get an SSL/TLS certificate from a certificate authority. AWS does not recommend a specific CA.

Note: If you're using a test environment, you can generate a self-signed certificate instead. Self-signed certificates aren't trusted by browsers and shouldn't be used in production environments.

17.    (Skip this step if you aren't using a test environment with a self-signed certificate.) Use the OpenSSL x509 command to generate a private key for the self-signed SSL certificate. In the following example, cert.key is the name of the private key.

$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/cert.key -out /etc/nginx/cert.crt

18.    Modify the /etc/nginx/conf.d/default.conf file as shown in the following example. Replace the following values:
/etc/nginx/cert.crt: the path to your SSL certificate
/etc/nginx/cert.key: the path to the private key that you generated for the SSL certificate
$ES_endpoint: your Elasticsearch endpoint. For more information, see Configuring Identity Providers.
$cognito_host: the Amazon Cognito user pool domain that you configured in step 2.

Note: You can use the sed command to assign $ES_endpoint and $cognito_host as variables, instead of replacing them directly in the default.conf file. For more information, see step 19.

server {
    listen 443;
    server_name $host;
    rewrite ^/$ https://$host/_plugin/kibana redirect;
 
    ssl_certificate           /etc/nginx/cert.crt;
    ssl_certificate_key       /etc/nginx/cert.key;
 
    ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;
 
 
    location ^~ /_plugin/kibana {
        # Forward requests to Kibana
        proxy_pass https://$ES_endpoint/_plugin/kibana;
 
        # Handle redirects to Amazon Cognito
        proxy_redirect https://$cognito_host https://$host;
 
        # Update cookie domain and path
        proxy_cookie_domain $ES_endpoint $host;
 
        proxy_set_header Accept-Encoding "";
        sub_filter_types *;
        sub_filter $ES_endpoint $host;
        sub_filter_once off;
 
        # Response buffer settings
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }
 
    location ~ \/(log|sign|error|fav|forgot|change) {
        # Forward requests to Cognito
        proxy_pass https://$cognito_host;
 
        # Handle redirects to Kibana
        proxy_redirect https://$ES_endpoint https://$host;
 
        # Handle redirects to Amazon Cognito
        proxy_redirect https://$cognito_host https://$host;
 
        # Update cookie domain
        proxy_cookie_domain $cognito_host $host;
    }
}

For example, the following configuration file uses these values:

Elasticsearch endpoint: vpc-mykibana-111xxx.us-east1.es.amazonaws.com
Cognito host: mydomain.auth.us-east-1.amazoncognito.com

server {
    listen 443;
    server_name $host;
    rewrite ^/$ https://$host/_plugin/kibana redirect;
 
    ssl_certificate           /etc/nginx/cert.crt;
    ssl_certificate_key       /etc/nginx/cert.key;
 
    ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;
 
 
    location ^~ /_plugin/kibana {
        # Forward requests to Kibana
        proxy_pass https://vpc-mykibana-111xxx.us-east1.es.amazonaws.com/_plugin/kibana;
 
        # Handle redirects to Amazon Cognito
        proxy_redirect https://mydomain.auth.us-east-1.amazoncognito.com https://$host;
 
        # Update cookie domain and path
        proxy_cookie_domain vpc-mykibana-111xxx.us-east1.es.amazonaws.com $host;
 
        proxy_set_header Accept-Encoding "";
        sub_filter_types *;
        sub_filter vpc-mykibana-111xxx.us-east1.es.amazonaws.com $host;
        sub_filter_once off;
 
        # Response buffer settings
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }
 
    location ~ \/(log|sign|error|fav|forgot|change) {
        # Forward requests to Cognito
        proxy_pass https://mydomain.auth.us-east-1.amazoncognito.com;
 
        # Handle redirects to Kibana
        proxy_redirect https://vpc-mykibana-111xxx.us-east1.es.amazonaws.com https://$host;
 
        # Handle redirects to Amazon Cognito
        proxy_redirect https://mydomain.auth.us-east-1.amazoncognito.com https://$host;
 
        # Update cookie domain
        proxy_cookie_domain mydomain.auth.us-east-1.amazoncognito.com $host;
    }
}

19.    (Optional) Use the sed command to assign the $ES_endpoint and $cognito_host variables. When you do this, you don't have to replace $ES_endpoint and $cognito_host in the /etc/nginx/conf.d/default.conf file. Example:

$ sudo sed -i 's/$ES_endpoint/vpc-mykibana-111xxx.us-east1.es.amazonaws.com' /etc/nginx/conf.d/default.conf
$ sudo sed -i 's/$cognito_host/mydomain.auth.us-east-1.amazoncognito.com' /etc/nginx/conf.d/default.conf

20.    Restart NGINX.

For instances launched with an Amazon Linux AMI, use this command:

$ sudo service nginx restart

For instances launched with an Amazon Linux 2 AMI, use this command:

$ sudo systemctl restart nginx.service

21.    Use your browser to access the NGINX IP or the DNS name. You're redirected to the Amazon Cognito login page.

22.    To log in to Kibana, enter your user name and temporary password. Then, change your password and log in again.