IBM Support

Secure Public NGINX Reverse Proxy for HCP Vault Dedicated (Workload Identity Federation)

How To


Summary

This guide walks through deploying and configuring an NGINX reverse proxy on an Amazon EC2 instance. It allows a private HCP Vault Dedicated cluster to support AWS Workload Identity Federation (WIF) by securely exposing only the required OIDC discovery and JWKS endpoints over the public internet, while keeping the rest of your Vault cluster private.

Environment

Architecture Overview

In an HCP Vault Dedicated private cluster, Vault is deployed within a HashiCorp Virtual
Network (HVN) and is accessible only through private connectivity (such as VPC peering or
AWS Transit Gateway).
When using Workload Identity Federation (WIF) with the Vault AWS secrets engine, Vault
authenticates to AWS without static access keys by generating short-lived OIDC JSON Web
Tokens (JWTs). However, AWS STS validates these tokens out-of-band by querying Vault's
OIDC discovery document (.well-known/openid-configuration) and public signing keys (.well-
known/keys) over the public internet.

This NGINX proxy resolves that requirement by acting as a public gateway strictly for OIDC
discovery:

AWS STS Service
│ HTTPS (Port 443) — Requests OIDC discovery & JWKS
▼
Customer AWS VPC (Public Subnet)
EC2 Instance with NGINX Reverse Proxy

  • Public Domain (e.g. vault-wif.example.com)
  • Valid Public SSL/TLS Certificate
  • Strict Path Whitelist (Blocks all other Vault APIs)
    │ Private HTTPS (Port 8200)
    │ Forwarded over VPC Peering / Transit Gateway (by hostname)
    ▼
    HashiCorp Virtual Network (HVN)

          Private HCP Vault Dedicated Cluster

    Security Guardrails


Restricted Endpoint Whitelisting: NGINX only proxies:

  • /v1/<namespace>/identity/oidc/plugins/.well-known/openid-configuration

  • /v1/<namespace>/identity/oidc/plugins/.well-known/keys

All other paths are blocked with HTTP 403 Forbidden (including /v1/sys/health and all secrets/auth APIs), ensuring your private Vault cluster remains protected.

Dynamic DNS Resolution: NGINX re-resolves the private Vault hostname every 30 seconds via the AWS VPC DNS resolver (169.254.169.253), ensuring changes in private Vault cluster IP addresses do not cause downtime.
/identity/oidc/plugins/.well-known/openid-
configuration
• /v1//identity/oidc/plugins/.well-known/keys
/identity/oidc/plugins/.well-known/openid-
configuration
• /v1//identity/oidc/plugins/.well-known/keys
/identity/oidc/plugins/.well-known/openid-
configuration
• /v1//identity/oidc/plugins/.well-known/keys
/identity/oidc/plugins/.well-known/openid-
configuration
• /v1//identity/oidc/plugins/.well-known/keys

Steps

Prerequisites

Before configuring NGINX, ensure the following infrastructure prerequisites are met:

1.1 Private HCP Vault Dedicated Cluster

• A running HCP Vault Dedicated cluster configured with private networking.
• Vault version 1.17+ (required for AWS secrets engine Workload Identity Federation).

1.2 AWS VPC Peering or AWS Transit Gateway to HCP HVN

Your AWS VPC must have private connectivity to the HashiCorp Virtual Network (HVN)
hosting your Vault cluster. This setup works identically with either AWS VPC Peering or AWS
Transit Gateway (TGW):

• Establish an active VPC Peering connection or attach your AWS Transit Gateway to
the HCP HVN.
• Ensure the route table associated with your proxy subnet contains a route pointing
your HVN CIDR block to the VPC Peering connection (pcx-...) or Transit Gateway
(tgw-...).
• Ensure the proxy subnet route table also has a default route to an Internet Gateway
(0.0.0.0/0 -> igw-...) for incoming public HTTPS traffic.

Official HashiCorp Documentation:
• Create an Amazon Web Services (AWS) Peering Connection:
https://developer.hashicorp.com/hcp/docs/hcp/networking/peering
• Create an Amazon Web Services (AWS) Transit Gateway Attachment:
https://developer.hashicorp.com/hcp/docs/hcp/networking/transit-gateway
 

EC2 Instance & Domain Setup (Overview)

2.1 EC2 Instance Provisioning
Deploy an EC2 instance in the public subnet of the peered VPC:
• Operating System: Ubuntu (22.04/24.04 LTS) or Amazon Linux 2023.
• Instance Size: t3.micro or t3.small is sufficient.
• Security Group Rules — Inbound Port 443 (HTTPS): Open to 0.0.0.0/0 (AWS STS
validates OIDC requests from dynamic AWS IP ranges).
• Security Group Rules — Outbound Port 8200: Allowed to the HCP HVN CIDR.

Official AWS Documentation:
• Amazon EC2 Getting Started Guide:
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html

2.2 Elastic IP and Public Domain Setup
AWS STS strictly requires that OIDC issuer URLs use valid, publicly trusted SSL/TLS
certificates signed by recognized Certificate Authorities (CAs). Self-signed certificates or raw
IP addresses are rejected by AWS STS.

• Allocate an Elastic IP: Associate an AWS Elastic IP with the EC2 instance so that its
public IP remains static.
• Configure DNS: In your DNS provider (e.g., Amazon Route 53), create an A Record
pointing your chosen public domain (e.g., vault-wif.example.com) to the Elastic IP of
your EC2 instance.
• SSL/TLS Certificate: Procure a valid SSL/TLS certificate for your domain (via your
organization's CA, ACM, or public certificate provider) and place the certificate and
private key files on the EC2 instance (e.g., at /etc/nginx/ssl/vault-proxy.crt and
/etc/nginx/ssl/vault-proxy.key).

Official AWS Documentation:
• Amazon Route 53 - Routing Internet Traffic to an Amazon EC2 Instance:
https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-ec2-instance.html
 

Step-by-Step NGINX Setup
Run the following commands directly on your EC2 instance.

Step 3.1: Install NGINX

For Ubuntu / Debian:
sudo apt-get update -y
sudo apt-get install -y nginx ca-certificates openssl

For Amazon Linux 2023 / RHEL / Fedora:
sudo dnf install -y nginx ca-certificates openssl

Step 3.2: Place Your SSL/TLS Certificate
Create the directory for your certificates and copy your valid public certificate and private
key:
sudo mkdir -p /etc/nginx/ssl
sudo chmod 700 /etc/nginx/ssl

#Place your certificate and private key (adjust paths as needed)

#sudo cp your-certificate.crt /etc/nginx/ssl/vault-proxy.crt

#sudo cp your-private.key /etc/nginx/ssl/vault-proxy.key# Secure key permissions

#Secure key permissions

sudo chmod 600 /etc/nginx/ssl/vault-proxy.key

Step 3.3: Create Shared Vault Proxy Parameters
Create the shared proxy configuration file /etc/nginx/vault-proxy-pass.inc.

Replace <YOUR_PRIVATE_VAULT_HOST> with your private HCP Vault cluster hostname (e.g., vault-
cluster-xxx.z1.hashicorp.cloud without https:// or port). On Amazon Linux / RHEL, replace
/etc/ssl/certs/ca-certificates.crt with /etc/pki/tls/certs/ca-bundle.crt.

sudo cat << 'EOF' | sudo tee /etc/nginx/vault-proxy-pass.inc

#Using a variable in proxy_pass ensures NGINX re-resolves the hostname dynamically
proxy_pass $vault_upstream;
proxy_http_version 1.1;
proxy_set_header Host <YOUR_PRIVATE_VAULT_HOST>;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_ssl_server_name on;
proxy_ssl_name <YOUR_PRIVATE_VAULT_HOST>;
proxy_ssl_verify on;
proxy_ssl_verify_depth 4;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
EOF

Substitute your private Vault hostname into the file:
sudo sed -i 's/<YOUR_PRIVATE_VAULT_HOST>/vault-cluster-
xxx.z1.hashicorp.cloud/g' /etc/nginx/vault-proxy-pass.inc

Step 3.4: Configure the NGINX Server Block
Create the server block configuration at /etc/nginx/conf.d/vault-proxy.conf.

Replace vault-wif.example.com with your public domain and vault-cluster-xxx.z1.hashicorp.cloud with
your private Vault hostname.

sudo cat << 'EOF' | sudo tee /etc/nginx/conf.d/vault-proxy.conf

server {
       listen 443 ssl;
      server_name vault-wif.example.com;
      ssl_certificate /etc/nginx/ssl/vault-proxy.crt;ssl_certificate_key /etc/nginx/ssl/vault-proxy.key;
      ssl_protocols TLSv1.2 TLSv1.3;

#Re-resolve the private Vault hostname every 30 seconds via AWS

VPC DNS resolver
resolver 169.254.169.253 valid=30s ipv6=off;
resolver_timeout 5s;

set $vault_upstream "https://vault-cluster-
xxx.z1.hashicorp.cloud:8200";

#WIF: Proxy only OIDC discovery and JWKS for any namespace

location ~ ^/v1/(.+/)?identity/oidc/plugins/.well-known/(openid-
configuration|keys)$ {
include /etc/nginx/vault-proxy-pass.inc;
}

#Block all other Vault API endpoints

location / {
return 403;
}
}
EOF

Step 3.5: Validate and Start NGINX
Test the configuration for syntax errors and start the NGINX service:

Test NGINX configuration syntax

sudo nginx -t

Enable and start the NGINX service

sudo systemctl enable nginx
sudo systemctl restart nginx

4. Verification & Testing
From your local workstation, run the following verification checks:

4.1 Verify Allowed OIDC Endpoints
Confirm that NGINX successfully proxies the OIDC discovery document and JWKS keys:

Check OIDC Discovery endpoint (replace 'admin' if using a custom

namespace)
curl -s https://vault-
wif.example.com/v1/admin/identity/oidc/plugins/.well-known/openid-
configuration

Check JWKS Keys endpoint

curl -s https://vault-
wif.example.com/v1/admin/identity/oidc/plugins/.well-known/keys

4.2 Verify Unauthorized Routes are Blocked
Ensure non-WIF paths (such as /v1/sys/health or /v1/sys/seal-status) are rejected with HTTP
403 Forbidden:
curl -s -o /dev/null -w "%{http_code}\n" https://vault-
wif.example.com/v1/sys/health

Expected output: 403

curl -s -o /dev/null -w "%{http_code}\n" https://vault-
wif.example.com/v1/sys/seal-status

Expected output: 403

5. Configuring Vault Workload Identity Federation (WIF)

Once your NGINX proxy is operational and serving the OIDC discovery endpoints, configure Vault and AWS IAM to establish Workload Identity Federation:

- Update Vault OIDC Plugin Issuer: Set the issuer URL in your Vault namespace to match your public NGINX domain (https://vault-wif.example.com).

- Create AWS IAM OIDC Provider: Configure an IAM OIDC Identity Provider in AWS using the URL https://vault-wif.example.com/v1/<namespace>/identity/oidc/plugins with the audience sts.amazonaws.com.

- Create IAM Role & Trust Policy: Create an AWS IAM role configured with a trust policy allowing sts:AssumeRoleWithWebIdentity from the OIDC provider.

- Configure Vault AWS Secrets Engine: Configure the AWS secrets engine in Vault with role_arn pointing to your IAM role, eliminating the need for long-lived static AWS credentials./identity/oidc/plugins
with audience sts.amazonaws.com.
• Create IAM Role & Trust Policy: Create an AWS IAM role configured with a trust
policy allowing sts:AssumeRoleWithWebIdentity from the OIDC provider.
• Configure Vault AWS Secrets Engine: Configure the AWS secrets engine in Vault with
role_arn pointing to your IAM role, eliminating the need for long-lived static AWS
credentials.

Additional Information

Official HashiCorp & AWS Documentation:
• HashiCorp Vault: Workload Identity Federation (WIF) with AWS Secrets Engine:
https://developer.hashicorp.com/vault/docs/secrets/aws#workload-identity-federation-wif
• HashiCorp Vault API: Configure Root IAM Credentials:
https://developer.hashicorp.com/vault/api-docs/secret/aws#configure-root-iam-credentials
• AWS IAM: Creating OpenID Connect (OIDC) Identity Providers:
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html
• AWS IAM: Creating a Role for Web Identity or OIDC:
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html

Document Location

Worldwide

[{"Type":"MASTER","Line of Business":{"code":"LOB77","label":"Automation Platform"},"Business Unit":{"code":"BU048","label":"IBM Software"},"Product":{"code":"SSD77S","label":"IBM Vault"},"ARM Category":[{"code":"a8mgJ0000000DoTQAU","label":"HCP Vault-\u003ECore"}],"ARM Case Number":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"0.6.0 up to 1.20.4;1.15.0 up to 1.20.2;1.16.0;1.16.24;1.16.25;1.16.26;1.16.27;1.18.0;1.18.13;1.18.14;1.18.15;1.18.5;1.19.0;1.19.10;1.19.11;1.19.8;1.19.9;1.20.0;1.20.2;1.20.3;1.20.4;1.20.5;1.21.0;4.2.0 - 5.4.0"}]

Document Information

Modified date:
04 November 2026

UID

ibm17295304