Nginx Reverse Proxy for Amazon OpenSearch Kibana with Ansible
Motivation
Amazon OpenSearch Service cluster instances run inside a Virtual Private Cloud (VPC). If you want to access the Kibana interface dedicated to one of these instances, you generally have two options. One is tunneling to an EC2 bastion host, which is relatively straightforward. However, a disadvantage of this approach is the need to share bastion host keys with clients. Another option is to set up a reverse proxy on a bastion host that points to the private OpenSearch Kibana endpoint.
This example demonstrates how you can set up access to Kibana using an Nginx reverse proxy and provision it with Ansible.
This example represents a basic setup that can serve as a foundation for future improvements. It does not include secure access configurations like SSL/TLS certificates or authentication. It uses HTTP between the client and the proxy server; for a production environment, using HTTPS in this context is highly recommended. While it’s an easier setup, it is also less secure.
Example
Inventory
First, you need to define your Ansible inventory with at least one variable (open_search_endpoint
) which should point to your Kibana instance. Notice that we have two EC2 instances in our inventory. One could be for a production environment, and the second for staging, for example.
[opensearch_proxies]
proxy-prod ansible_host=ec2-X-X-X-X.compute-1.amazonaws.com open_search_endpoint="http://your-prod-opensearch-kibana-endpoint.com"
proxy-staging ansible_host=ec2-Y-Y-Y-Y.compute-1.amazonaws.com open_search_endpoint="http://your-staging-opensearch-kibana-endpoint.com"
Main Playbook
Next, we define the main Ansible playbook, which is quite straightforward. For it to work, you need to have the configuration files (default.conf.j2
and a basic nginx.conf
) located in your Ansible playbook’s path.
---
- name: Setup Nginx Reverse Proxy for OpenSearch Kibana
hosts: opensearch_proxies
become: yes
tasks:
- name: Update apt cache (Debian/Ubuntu)
ansible.builtin.apt:
update_cache: yes
when: ansible_os_family == "Debian"
- name: Install Nginx (Debian/Ubuntu)
ansible.builtin.apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install Nginx (RedHat/CentOS)
ansible.builtin.yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Ensure Nginx service is running and enabled
ansible.builtin.systemd:
name: nginx
state: started
enabled: yes
- name: Copy default Nginx configuration for Kibana proxy
ansible.builtin.template:
src: default.conf.j2 # This file needs to be in your files/templates directory
dest: /etc/nginx/sites-available/default
mode: '0644'
notify: Reload Nginx
- name: Enable site by symlinking
ansible.builtin.file:
src: /etc/nginx/sites-available/default
dest: /etc/nginx/sites-enabled/default
state: link
notify: Reload Nginx
- name: Remove default Nginx welcome page config (if present)
ansible.builtin.file:
path: /etc/nginx/conf.d/default.conf
state: absent
notify: Reload Nginx
handlers:
- name: Reload Nginx
ansible.builtin.systemd:
name: nginx
state: reloaded
Default Configuration
For default.conf.j2
, we are using a simple proxy pass. If you want a more secure connection, this is where you would configure HTTPS. This file should be placed in your templates
directory (e.g., playbook_directory/templates/default.conf.j2
).
# templates/default.conf.j2
server {
listen 80;
server_name _; # Listen on all hostnames or specify your domain
location / {
proxy_pass /; # Note the trailing slash to correctly proxy paths
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# Add headers to avoid issues with Kibana
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Ensure Kibana URLs are handled correctly if it expects a specific base path
# proxy_redirect default; # Might be needed if Kibana redirects
}
}
Nginx Configuration
This typically refers to the main nginx.conf
file, which is often included with the Nginx installation. The key part for our setup is ensuring that sites-enabled
configurations are included. You might not need to explicitly manage this file via Ansible if the default Nginx installation already includes the necessary include
directives. However, if you need to customize global Nginx settings (like worker_processes
or logging), you would place a template for it (e.g., nginx.conf.j2
) in your templates
directory and copy it to /etc/nginx/nginx.conf
with Ansible.
# /etc/nginx/nginx.conf (Example content for completeness)
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*; # This line ensures our 'default' site config is loaded
}
Enjoy Reading This Article?
Here are some more articles you might like to read next: