Skip to content

Scripts: Configure Wordpress wp-config.php using AWS Secrets Manager Script


Python


Wordpress Script Description


This script was designed to run on freshly deployed Wordpress server. Its function is to make a request to the AWS Secrets Manager to get the proper database credentials, and then using the /var/www/html/wordpress/wp-config-sample.php file as a base, it will write a new /var/www/html/wordpress/wp-config.php file inputing the credentials stored in the Secrets Manager directly into the wp-config.php file. This negates the necessity of having a hard coded username and password sitting in the AMI. The script performs the following actions:


1.    Environment Check:
When the Wordpress instance is instantiated, the following user-data is executed:

#cloud-boothook
#!/bin/bash
sudo echo "STAGE" | sudo tee --append /etc/environment
sudo systemctl stop httpd
sudo python3 /tmp/wp_config_secrets_manager.py
sudo rm -fr /tmp/wp_config_secrets_manager.py
sudo chown -R apache:apache /var/www/html/wordpress
sudo chmod 664 /var/www/html/wordpress/.htaccess
sed -i ':a;N;$!ba;s/AllowOverride\ None/AllowOverride\ ALL/2' /etc/httpd/conf/httpd.conf
sudo systemctl start httpd
sudo setenforce 0

The purpose of this user-data script is to set an environment type that the python script below will utilize to determine the proper deployment environment and type. In this case, the value of STAGE is written to the /etc/environment file. Apache is then stopped, this python script, which gathers the database credentials and writes the wp-config.php file is executed, and then removed. Next, permissions are set on the /var/www/html/wordpress directory, and the AllowOverride ALL apache directive is set. Last Apache is restarted, and SELinux is disabled.


1.    get_env() Function:
Once executed the first operation that the script performs is to run the get_env() function.

# Determine the environment type that we are configuring
wp_envion = get_env()

This function will read the contents of /etc/environment, and pull the value being set to DEV, STAGE or PROD. Based on the environment type set by the user-data script, the SecretId to query from the Secrets Manager service is retrieved, and then returned back to the calling variable. In this case after the function execution, wp_envion would contain Wordpress/Stage as the value.


2.    get_secret() Function:
Next, the script will pass the returned value, containing the SecretId (Wordpress/Stage) to the get_secret() function.

# Get credentials from Creds store:
cred_response = get_secret(wp_envion)
wp_user = cred_response['username']
wp_pass = cred_response['password']
wp_db_name = cred_response['dbname']
wp_host = cred_response['host']

The get_secret() function will make the request to the Secret Manager service for the secrets key:value payload specified by the returned get_env() SecretId value (Wordpress/Stage). It will take the response of that request, being a JSON object that contains the returned secrets stored values along with the secrets meta-data, and it will pull the SecretString key:value pair from the object, which contains the unencrypted values of all key:pairs stored in the returned Secrets Manager Secret, jsonify it, and return the new JSON object that now only contains the SecretString data. The SecretString data is simply a JSON object containing all of the secret key value pairs that were retrieved from the Secrets Manager Service. Next the script will parse the cred_response variable that now contains that JSON object and will parse it to set the values of the wp_user, wp_pass, wp_db_name, and wp_host variables based on the returned payload. After this functions execution cred_response would contain:

 {
    "username": "secret_username_value",
    "password": "secret_password_value",
    "dbname": "database_name",
    "host": "host_name"
 }

The wp_user variable would contain just the username value being secret_username_value, wp_password would contain secret_password_value, etc.. These values all correlate back to the object that is stored in the Secrets Manager Service


Secrets Manager Secret


3.    wp_config() Function:
Last, the script will pass the wp_user, wp_pass, wp_db_name and wp_host values, to the wp_config() function.

# Write the new config
write_config = wp_config(wp_user, wp_pass, wp_db_name, wp_host)

This function will read the /var/www/html/wordpress/wp-config-sample.php file, and line by line write each read line to a new file located in /var/www/html/wordpress/wp-config.php, replacing the username, password, database_name, and database_host values collected from the Secrets Manager service, directly into the new wp-config.php file. At this point the script execution would halt successfully, a new wp-config.php will have been written to the Wordpress directory, and when apache is restarted via the user-data script, Wordpress should be up, running, and properly connected to its database.


Python Script


import boto3  # Required to interact with AWS
import json   # Required for return object parsing
import re     # Required for line substitution in config parsing
from botocore.exceptions import ClientError


def get_env():
    '''Function to determine Environment variable'''

    # Get the environment type
    environment_file = "/etc/environment"
    environment = open(environment_file, "r")
    for line in environment:
        local_env = line

    local_env = str(local_env).upper()

    # Return the environment type
    if 'DEV' in local_env:
        secret_name = 'Wordpress/Dev'
    elif 'STAGE' in local_env:
        secret_name = 'Wordpress/Stage'
    else:
        secret_name = 'Wordpress/Prod'

    # Return the environment value:
    return secret_name


def get_secret(secret_name):
    '''This function will grab the username and password from the secure creds store'''

    endpoint_url = "https://secretsmanager.us-east-2.amazonaws.com"
    region_name = "us-east-2"

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name,
        endpoint_url=endpoint_url
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
        if e.response['Error']['Code'] == 'ResourceNotFoundException':
            print("The requested secret " + secret_name + " was not found")
        elif e.response['Error']['Code'] == 'InvalidRequestException':
            print("The request was invalid due to:", e)
        elif e.response['Error']['Code'] == 'InvalidParameterException':
            print("The request had invalid params:", e)
    else:
        # Decrypted secret using the associated KMS CMK
        # Depending on whether the secret was a string or binary, one of these fields will be populated
        if 'SecretString' in get_secret_value_response:
            secret = json.loads(get_secret_value_response['SecretString'])
            return secret
        else:
            binary_secret_data = get_secret_value_response['SecretBinary']
            return binary_secret_data


def wp_config(user, password, db_name, host):
    '''This function will parse and replace the values in the wp-config files from the values stored in the credentials store'''

    # Define the input and output files:
    sample_file = open("/var/www/html/wordpress/wp-config-sample.php", "r")
    config_file = open("/var/www/html/wordpress/wp-config.php", "w")

    # sample_file = open("wp-config-sample.php", "r")
    # config_file = open("wp-config.php", "w")

    # Now lets edit the sample file and write the new file:
    for line in sample_file:
        if 'database_name_here' in line:
            new_line = re.sub('database_name_here', db_name, line)
            config_file.write(new_line)
        elif 'username_here' in line:
            new_line = re.sub('username_here', user, line)
            config_file.write(new_line)
        elif 'password_here' in line:
            new_line = re.sub('password_here', password, line)
            config_file.write(new_line)
        elif 'localhost' in line:
            new_line = re.sub('localhost', host, line)
            config_file.write(new_line)
        else:
            config_file.write(line)


# Determine the environment type that we are configuring
wp_envion = get_env()

# Get credentials from Creds store:
cred_response = get_secret(wp_envion)
wp_user = cred_response['username']
wp_pass = cred_response['password']
wp_db_name = cred_response['dbname']
wp_host = cred_response['host']


# Write the new config
write_config = wp_config(wp_user, wp_pass, wp_db_name, wp_host)


Python Script Download


wp_config_secrets_manager.py


Comments