/letsencrypt-client

Docker container that can be paired with a web server (e.g. Nginx) and/or AWS ELB and downloads certificates

Primary LanguagePythonGNU General Public License v3.0GPL-3.0

LETSENCRYPT FOR DOCKER

Developed by the Center for Virtualization and Applied Spatial Technologies (CVAST), University of South Florida

This tool lets you download and renew certificates. It can be paired with Docker containers running web servers (e.g. Nginx).
It also works for servers running on Amazon Web Services (AWS) behind an Elastic Load Balancer (ELB).

Additionally, it can be used to register with LetsEncrypt using your email address
(only required when running behind an AWS ELB).

Based on:

Tested on:

  • Localhost (registration only)
  • Single AWS EC2 instance paired with an NginX container
  • AWS ECS cluster running behind an Elastic Load Balancer (also paired with an Nginx container)

Usage

Global Environment Variables

  • Required:
    • PRODUCTION_MODE: True or False. Use LetsEncrypt's staging or production server to register or get a certificate.

Commands

-h or --help or help: Display help text

get_certificate: Automatically download or renew certificate for domain(s) provided through the DOMAIN_NAMES environment variable.

  • Additional Environment Variables
    • Both regular and AWS ELB mode:

      • Required:
        • DOMAIN_NAMES: List of domain names (in a regular string).
      • Optional:
        • MODE: regular|elb. Default = regular. Set to 'elb' when running behind an AWS Elastic Load Balancer.
        • FORCE_RENEWAL: True|False. Force issue of a certificate, even if it is not due for renewal. Default = False.
        • PERSISTENT_MODE: True|False. Keep this Docker container running as a service in order to have your certificates renewed automatically. Default = False.
        • ADDITIONAL_PARAMETERS: Additional parameters for either Certbot or letsencrypt-aws, other than those controlled by FORCE_RENEWAL and PERSISTENT_MODE.
        • LETSENCRYPT_RENEWAL_SLEEP_TIME: Interval between renewal checks. Default = 24 hours.
    • Regular mode:

      • Required:
        • LETSENCRYPT_EMAIL: Email address to be registered with LetsEncrypt.
      • Optional:
        • WEB_ROOT: Path used as root for ACME challange. Default = /var/www. Mount this folder to both the LetsEncrypt and web server container (see volume 'web-root' in docker-compose.yml below). Also point to this path in your web server configuration, e.g.: location ~ /.well-known/acme-challenge { allow all; root /var/www; }
    • AWS ELB mode:

      • Required:
        • ELB_NAME: Elastic Load Balancer name.
        • PRIVATE_KEY_PATH: Location of your LetsEncrypt/ACME account private key (local or AWS S3). Format: 'file:///path/to/key.pem' (local file Unix), 'file://C:/path/to/key.pem' (local file Windows), or 's3://bucket-name/object-name'. The key should be a PEM formatted RSA private key.
        • AWS_DEFAULT_REGION: The AWS region your services are running in.

register:
Manually registers the provided email address with LetsEncrypt/ACME. Returns a private key in stout, or in a file if PRIVATE_KEY_PATH is provided.

Use this when running in ELB mode. In all other situations the registration is done automatically by Certbot. In that case the private key is saved to /etc/letsencrypt.

  • Additional Environment Variables

    • Required:
      • LETSENCRYPT_EMAIL: Email address to be registered with LetsEncrypt.
      • AWS_DEFAULT_REGION: (Only if you use AWS S3 for storage) The AWS region your services are running in.
    • Optional:
      • PRIVATE_KEY_PATH: Location to save your LetsEncrypt/ACME account private key to (local or AWS S3). Format: 'file:///path/to/key.pem' (local file Unix), 'file://C:/path/to/key.pem' (local file Windows), or 's3://bucket-name/object-name'.

Volumes

When pairing cvast-letsencrypt with a web server container, a few volumes need to be created to allow communication between your containers.

docker-compose.yml when not behind an AWS ELB:
version: '2'
services:   

    nginx:
      restart: always
      image: nginx
      ports:
        - '80:80'
        - '443:443'
      volumes:
        - web-root:/var/www
        - letsencrypt-config:/etc/letsencrypt

    letsencrypt:
      image: cvast/cvast-letsencrypt:1.0
      command: get_certificate
      volumes:
        - web-root:/var/www
        - letsencrypt-config:/etc/letsencrypt
        - letsencrypt-log:/var/log/letsencrypt
      environment:
        - LETSENCRYPT_EMAIL=example@mail.edu
        - DOMAIN_NAMES=example.com www.example.com
        - PRODUCTION_MODE=False
        # - PRIVATE_KEY_PATH=s3://bucket-name/object-name.pem
        # - PRIVATE_KEY_PATH=file:///path/to/object-name.pem
        - AWS_ACCESS_KEY_ID=
        - AWS_SECRET_ACCESS_KEY=
        - AWS_DEFAULT_REGION=
        - FORCE_RENEWAL=False
        - PERSISTENT_MODE=False

  volumes:
    web-root:
    letsencrypt-config:
    letsencrypt-log:
Configuration when behind an AWS ELB:

Same as docker-compose.yml shown above, but without the nginx-root volume (ACME challange is done on Route 53 level instead of your web server).

AWS IAM Policy

AWS ELB

When running behind an ELB, certain priviledges are required. Sample IAM policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets",
                "route53:GetChange",
                "route53:GetChangeDetails",
                "route53:ListHostedZones"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:SetLoadBalancerListenerSSLCertificate"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "iam:ListServerCertificates",
                "iam:GetServerCertificate",
                "iam:UploadServerCertificate"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name/optional-folder-name/*"
            ]
        }
    ]
}
Non-AWS access

Alternatively (e.g. when not running on an AWS server, but still using an S3 bucket for storage), you can create a user policy that allows access. Be sure to specify these envrionment variables in the letsencrypt container:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_DEFAULT_REGION
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::cvast-config/letsencrypt/*"
        }
    ]
}