AWS Elastic Beanstalk .ebextensions File creation not working (apache config)

6.7k views Asked by At

Following the instructions at https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-singleinstance-php.html I've been trying to add my SSL certificate to allow for https for my single instance environment.

I've spent a ridiculous amount of time on this and it's driving me crazy.

My important findings are:

  • after deployment, if the extensions script execute without error, the /etc/httpd/conf.d/ssl.conf is not created. Or perhaps it is overwritten later on. In any case, the SSL certificate is not working
  • after deployment, if for instance, I try to create 2 of the same ssl.conf files - causing an error (module ssl_module is already loaded, skipping), the file is created

I was testing by SSHing onto the EC2 instance after redeploying and checking /etc/httpd/conf.d/.

I'm running on the platform: PHP 7.4 running on 64bit Amazon Linux 2/3.1.2

This is the first time I am working with SSL certificates as well as AWS so any help would be much appreciated.

https-instance.config:

packages:
  yum:
    mod_ssl: []

files:
  /etc/pki/tls/certs/server.crt:
    mode: "000400"
    owner: root
    group: root
    content: |
      -----BEGIN CERTIFICATE-----
      1
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      2
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      3
      -----END CERTIFICATE-----

  /etc/pki/tls/certs/server.key:
    mode: "000400"
    owner: root
    group: root
    content: |
      -----BEGIN RSA PRIVATE KEY-----
      1
      -----END RSA PRIVATE KEY-----

  "/etc/httpd/conf.d/ssl.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      LoadModule ssl_module modules/mod_ssl.so
      Listen 443
      <VirtualHost *:443>
        <Proxy *>
          Order deny,allow
          Allow from all
        </Proxy>

        SSLEngine on
        SSLCertificateFile "/etc/pki/tls/certs/server.crt"
        SSLCertificateKeyFile "/etc/pki/tls/certs/server.key"
        SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
        SSLProtocol All -SSLv2 -SSLv3
        SSLHonorCipherOrder On
        SSLSessionTickets Off

        Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
        Header always set X-Frame-Options DENY
        Header always set X-Content-Type-Options nosniff

        ProxyPass / http://localhost:80/ retry=0
        ProxyPassReverse / http://localhost:80/
        ProxyPreserveHost on
        RequestHeader set X-Forwarded-Proto "https" early
      </VirtualHost>

https-instance-single.config (not important for this issue)

Resources:
  sslSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
      IpProtocol: tcp
      ToPort: 443
      FromPort: 443
      CidrIp: 0.0.0.0/0

2

There are 2 answers

1
guimauve On BEST ANSWER

To create / modify any file or execute any script post deployment, do the following (I already answered a similar question about modifying nginx configuration on deployment here). Same applies for your apache configuration.

You need to create files in /tmp then mv them to their final location using a script.

The following applies for an Amazon Linux 2 environment:

Source: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/platforms-linux-extend.html

Scripts are executed from subfolders in .platform that you have to place at the root of your project, like so:

~/your-app/
|-- Procfile
|-- readme.md
|-- .ebextensions/
|   |-- 01_write_some_files.config        
`-- .platform/
    |-- hooks
        `-- postdeploy
            `-- 01_move_some_files.sh        # Executed post deployment

01_write_some_files.config

Create a .config file at the root of .ebextensions.

  1. Create your files in /tmp:
files:
  /tmp/someFolder/server.crt:
     mode: "000644"
     owner: root
     group: root
     content: |
       # your file content

  /tmp/someFolder/server.key:
     mode: "000644"
     owner: root
     group: root
     content: |
       # your file content

  # Do the same for all your files

01_move_some_files.sh

Create a small script in .platform/hooks/postdeploy and change permissions to 755.

#!/usr/bin/bash

# Move the files you created in /tmp into the desired directories. 
sudo mv /tmp/someFolder/server.crt /etc/pki/tls/certs/server.crt

# other bash commands
0
Zags On

As of AWS Linux 2, you are severely restricted in the locations that you can write files using bash directly (such as with output redirection).

The intended solution for webserver config is for you to put files in subdirectories of .platform, namely as .platform/httpd for Apache or .platform/nginx for Nginx.

If you need to write other files, you have two options. First, commands and container_commands in .ebextensions can still write files to /tmp, so you can write a file to /tmp and then move it to where you want it to go.

A better solution is to write them with your own script that you invoke. So, for example, put the following in one of your .ebextensions/FILENAME.config files:

container_commands:
    # ...
    03_write_files:
        command: |
            source $PYTHONPATH/activate
            python .ebextensions/write_files.py

Then, have a script in .ebextensions/write_files.py that writes the files:

#!/bin/python3
with open("file/1/path", "w") as f:
    f.write("file contents")
with open("file/2/path", "w") as f:
    f.write("file contents")

Warning: Be very careful if you are generating files in your project directory on deploy. See Elastic Beanstalk deleting generated files on config changes for more information.