AWS CloudFormation EC2 UserData example to install NGINX Plus on Ubuntu 20.04 LTS using AWS SecretsManager

Introduction

There are a number of ways to automate NGINX Plus instance creation on AWS - you can create a custom AMI, or build a container image. Tools like Ansible, terraform, Pulumi etc. can also install and configure NGINX Plus.

This example was tested in CloudFormation template that creates an Ubuntu 20.04 LTS EC2 instance and the uses UserData script to install NGINX Plus.

A critical part of NGINX Plus install is to copy your NGINX Plus SSL Certificate and Key - required for access to the NGINX Plus private repository - into /etc/nginx/ssl/. There a few different ways to achieve this, but the AWS SecretsManager service provides a lot of audit, access control, and security capabilities.

You can use the snippets below in your AWS CloudFormation templates to retrieve the NGINX certificate and key from AWS, configure the NGINX repository on your EC2 Instance, and then download and install the software.

Prerequisites

Store your NGINX Plus Certificate and Key in AWS Secrets Manager - in my example I'm storing the certificate and key in separate secret objects. 

Create an IAM Role and policy to allow your EC2 Instance to access the secrets. My Policy looks like this: 

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": "arn:aws:secretsmanager:*:<account ID>:secret:*"
    }
  ]  
}

Obviously you may want to alter the the scope of the resource access.

Attach this policy to a role and assign the role to your EC2 Instance in the CFT:

Create a parameter (you could skip this and just add the name to the Instance Profile in the next step, but parameters can be useful if you want to change things at deploy time):

NginxInstanceRole:
  Description: Role for instance Instance
  Type: String
  Default: EC2Secrets

Reference parameter in the EC2 instance profile:

NGInstanceProfile:
  Type: AWS::IAM::InstanceProfile
  Properties: 
   InstanceProfileName: !Sub "nginx-instance-profile-${AWS::StackName}"
   Path: /
   Roles: 
    - !Ref NginxInstanceRole

Reference the instance profile in the EC2 block:

# EC2 instance which will have access for http and ssh
 EC2Instance:
  Type: 'AWS::EC2::Instance'
  Properties:
   InstanceType: !Ref InstanceType
   SubnetId: !Ref SubnetID   
   SecurityGroupIds:
    - !Ref WebSecurityGroupID
    - !Ref AdminSecurityGroupID
   KeyName: !Ref KeyPairName
   ImageId: !Ref InstanceImageId
   IamInstanceProfile: !Ref NginxInstanceRole

UserData Block

Now in the UserData section of your EC2 instance spec the following commands will:

  • Install the jq package (to parse some output)
  • Install the the AWS CLI  
  • Pull the secrets using 'aws secretsmanager get-secrets-value'
  • Use the jq package and tr to get the files into the correct format (there may be a better way to manage this). 
  • Follow the standard NGINX plus install (add NGINX repo etc)
  • Start the NGINX Plus service

 

UserData: 
    Fn::Base64: !Sub |
     #!/bin/bash -xe
     sudo apt-get update -y # good practice to update existing packages
     sudo apt-get install -y awscli
     sudo apt install -y jq 
     sudo mkdir /etc/ssl/nginx
     # install the key and secret 
     aws secretsmanager get-secret-value --secret-id nginxcert --region ${AWS::Region} | jq --raw-output '.SecretString'| tr -d '"{}' | sudo tee /etc/ssl/nginx/nginx-repo.crt
     aws secretsmanager get-secret-value --secret-id nginxkey --region ${AWS::Region} | jq --raw-output '.SecretString'| tr -d '"{}' | sudo tee /etc/ssl/nginx/nginx-repo.key
     # Add the repo
     sudo wget https://cs.nginx.com/static/keys/nginx_signing.key && sudo apt-key add nginx_signing.key 
     sudo wget https://cs.nginx.com/static/keys/app-protect-security-updates.key && sudo apt-key add app-protect-security-updates.key
     sudo apt-get install -y apt-transport-https lsb-release ca-certificates
     printf "deb https://pkgs.nginx.com/plus/ubuntu `lsb_release -cs` nginx-plus\n" | sudo tee /etc/apt/sources.list.d/nginx-plus.list
     sudo wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx
     # Install and start 
     sudo apt-get update -y # good practice to update existing packages
     sudo apt-get install nginx-plus -y # install web server   
     sudo systemctl start nginx.service # start webserver

This should produce a working NGINX Plus install. 

Comment below if you'd like a complete working CFT example linked to this article.

Published Nov 09, 2021
Version 1.0
No CommentsBe the first to comment