diff --git a/README.md b/README.md index 56d9c6d4..4a5d5b0e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ This is the AWS layer that provides an API for Clinical Prescription Tracker. - `packages/common/testing` Module that contains some test data used for tests in other modules. - `packages/sandbox/` Returns [static data](./packages/sandbox/examples/GetMyPrescriptions/Bundle/success.json) from the Sandbox. - `packages/statusLambda/` Returns the status of the getMyPrescriptions endpoint. -- `privateCA/` Contains script to create self signed CA certificate and a client certificate used for mutual TLS. - `SAMtemplates/` Contains the SAM templates used to define the stacks. - `scripts/` Utilities helpful to developers of this specification. - `.devcontainer` Contains a dockerfile and vscode devcontainer definition. diff --git a/privateCA/.gitignore b/privateCA/.gitignore deleted file mode 100644 index 7e452ae9..00000000 --- a/privateCA/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -private -crl -config -certs -certs_backup_* -private_backup_* diff --git a/privateCA/README.md b/privateCA/README.md deleted file mode 100644 index 9c06a02a..00000000 --- a/privateCA/README.md +++ /dev/null @@ -1,14 +0,0 @@ -This folder contains scripts to initialize the private CA used for mutual TLS in each environment. - -The script ./create_certs.sh creates new self signed CA certificate and a client certificate. These are valid for 1 year. -The private keys and certificates for these are stored in AWS secrets manager. -The existing truststore file is downloaded from S3 and the new CA certificate is appended to the end of the existing one before uploading to enable old certificates to still to be used. -The public CA cert is uploaded to s3://TRUSTSTORE_BUCKET_NAME/truststore.pem and s3://TRUSTSTORE_BUCKET_NAME/sandbox-truststore.pem where it used by API gateway as a truststore to indicate what certificates should be trusted for mutual TLS. - -Before running the script, you should set environment variable AWS_PROFILE to indicate what environment this is being run for. -You should pass the environment name using the -e flag when calling the script. -By default the script does not upload new secrets or truststore files. If you want to do this, you must pass flag `-d false`. - -Existing certificates and keys are backed up locally before new ones are uploaded. - -To get API gateway to use the new truststore, you must do a redeploy of the cloud formation stack using github action. diff --git a/privateCA/create_certs.sh b/privateCA/create_certs.sh deleted file mode 100755 index 3f2ce767..00000000 --- a/privateCA/create_certs.sh +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/env bash - -while getopts e:d: flag -do - case "$flag" in - e) environment=${OPTARG};; - d) dry_run_param=${OPTARG};; - *) echo "usage: $0 [-e] environment [-d] dry run" >&2 - exit 1 ;; - esac -done - -if [ "$dry_run_param" = "false" ]; then - DRY_RUN=false -else - DRY_RUN=true -fi - -if [ "$environment" = "" ]; then - echo "You must pass in an environment name using the e flag" - exit 1 -fi - -readonly BASE_DIR=$(pwd) -readonly CERTS_DIR="${BASE_DIR}/certs" -readonly KEYS_DIR="${BASE_DIR}/private" -readonly DATESTAMP=$(date +%Y%m%d_%H%M%S) -readonly BACKUP_CERTS_DIR="${BASE_DIR}/certs_backup_${DATESTAMP}" -readonly BACKUP_KEYS_DIR="${BASE_DIR}/private_backup_${DATESTAMP}" -readonly CRL_DIR="${BASE_DIR}/crl" -readonly CONFIG_DIR="${BASE_DIR}/config" - -# OpenSSL Configs -readonly CA_CERT_SIGNING_CONFIG="openssl-ca.conf" -readonly CERT_VALIDITY_DAYS="365" - -# CA config -readonly CA_NAME="ca" -readonly CA_CERTIFICATE_SUBJECT="/C=GB/ST=Leeds/L=Leeds/O=nhs/OU=clinical tracker private CA/CN=clinical tracker private CA $(date +%Y%m%d_%H%M%S)" - -readonly CERT_PREFIX="${environment}-" -readonly CERT_PREFIX_CI="ci" -readonly CERT_PREFIX_SANDBOX="sandbox" - -readonly CLIENT_CERT_SUBJECT_PREFIX="/C=GB/ST=Leeds/L=Leeds/O=nhs/OU=clinical tracker private CA/CN=client-cert-" - -# v3 extensions -readonly V3_EXT="$BASE_DIR/v3.ext" - -function generate_crl { - openssl ca -config openssl-ca.conf -gencrl -out "$CRL_DIR/$CA_NAME.crl" -} - -function convert_cert_to_der { - local readonly cert_name="$1" - echo "@ Converting $cert_name to DER format..." - openssl x509 -outform DER -in "$CERTS_DIR/$cert_name.pem" -out "$CERTS_DIR/$cert_name.crt" -} - -function generate_key { - local readonly key_name="$1" - echo "@ Generating key '$key_name'..." - openssl genrsa -out "$KEYS_DIR/$key_name.key" 2048 -} - -function generate_ca_cert { - local readonly key_name="$1" - echo "@ Generating CA certificate..." - openssl req -new -x509 -days "$CERT_VALIDITY_DAYS" -config "$BASE_DIR/$CA_CERT_SIGNING_CONFIG" \ - -key "$KEYS_DIR/$key_name.key" \ - -out "$CERTS_DIR/$key_name.pem" -outform PEM -subj "$CA_CERTIFICATE_SUBJECT" - - convert_cert_to_der "$key_name" -} - -function create_csr { - local readonly key_name="$1" - local readonly client_description="$2" - - if [ "$key_name" = "apigee_client_cert" ] - then - echo "@ Creating CSR for '$key_name'..." - openssl req -config "$BASE_DIR/$SMARTCARD_CERT_SIGNING_CONFIG" -new \ - -key "$KEYS_DIR/$key_name.key" \ - -out "$CERTS_DIR/$key_name.csr" -outform PEM \ - -subj "${CLIENT_CERT_SUBJECT_PREFIX}${CERT_PREFIX}${CERT_PREFIX_CI}${client_description}" - elif [ "$key_name" = "apigee_client_cert_sandbox" ] - then - echo "@ Creating CSR for '$key_name'..." - openssl req -config "$BASE_DIR/$SMARTCARD_CERT_SIGNING_CONFIG" -new \ - -key "$KEYS_DIR/$key_name.key" \ - -out "$CERTS_DIR/$key_name.csr" -outform PEM \ - -subj "${CLIENT_CERT_SUBJECT_PREFIX}${CERT_PREFIX}${CERT_PREFIX_SANDBOX}${client_description}" - fi -} - -function sign_csr_with_ca { - local readonly key_name="$1" - echo "@ Using CSR to generate signed cert for '$key_name'..." - openssl ca -batch \ - -config "$BASE_DIR/$CA_CERT_SIGNING_CONFIG" -policy signing_policy -extensions signing_req \ - -keyfile "$KEYS_DIR/$CA_NAME.key" -cert "$CERTS_DIR/$CA_NAME.pem" \ - -days "$CERT_VALIDITY_DAYS" -out "$CERTS_DIR/$key_name.pem" -in "$CERTS_DIR/$key_name.csr" \ - -notext # don't output the text form of a certificate to the output file -} - - -function generate_ca_signed_cert { - local readonly key_name="$1" - local readonly cert_subject="$2" - - create_csr "$key_name" "$cert_subject" - sign_csr_with_ca "$key_name" -} - - -function generate_client_cert { - local readonly name="$1" - - local readonly description="-apigee-client-cert" - generate_key "$name" - generate_ca_signed_cert "$name" "$description" - convert_cert_to_der "$name" -} - -echo "Going to create mutual TLS certs with these details" -echo "AWS_PROFILE: ${AWS_PROFILE}" -echo "CERT_PREFIX ${CERT_PREFIX}" -echo "DRY_RUN ${DRY_RUN}" -read -p "Press any key to resume or press ctrl+c to exit ..." - -# Recreate output dirs -rm -rf "$CERTS_DIR" "$KEYS_DIR" "$CRL_DIR" "$CONFIG_DIR" -mkdir "$CERTS_DIR" "$KEYS_DIR" "$CRL_DIR" "$CONFIG_DIR" "$BACKUP_CERTS_DIR" "$BACKUP_KEYS_DIR" - - -# Create database and serial files -touch "$CONFIG_DIR/index.txt" -echo '1000' > "$CONFIG_DIR/crlnumber.txt" -echo '01' > "$CONFIG_DIR/serial.txt" - -# Generate CA key and self-signed cert -echo "Generating CA credentials..." -generate_key "$CA_NAME" -generate_ca_cert "$CA_NAME" - -generate_client_cert "apigee_client_cert" -generate_client_cert "apigee_client_cert_sandbox" - -CA_KEY_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`CAKeySecret`].OutputValue' --output text) -CA_CERT_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`CACertSecret`].OutputValue' --output text) -CLIENT_KEY_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`ClientKeySecret`].OutputValue' --output text) -CLIENT_CERT_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`ClientCertSecret`].OutputValue' --output text) -CLIENT_SANDBOX_KEY_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`ClientSandboxKeySecret`].OutputValue' --output text) -CLIENT_SANDBOX_CERT_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`ClientSandboxCertSecret`].OutputValue' --output text) -TRUSTSTORE_BUCKET_ARN=$(aws cloudformation describe-stacks \ - --stack-name account-resources \ - --query 'Stacks[0].Outputs[?OutputKey==`TrustStoreBucket`].OutputValue' --output text) -TRUSTSTORE_BUCKET_NAME=$(echo ${TRUSTSTORE_BUCKET_ARN} | cut -d ":" -f 6) - -echo "Backing up existing secrets to local file" - -aws secretsmanager get-secret-value \ - --secret-id ${CA_KEY_ARN} \ - --query SecretString \ - --output text > ${BACKUP_KEYS_DIR}/${CA_NAME}.key - -aws secretsmanager get-secret-value \ - --secret-id ${CA_CERT_ARN} \ - --query SecretString \ - --output text > ${BACKUP_CERTS_DIR}/${CA_NAME}.pem - -aws secretsmanager get-secret-value \ - --secret-id ${CLIENT_KEY_ARN} \ - --query SecretString \ - --output text > ${BACKUP_KEYS_DIR}/apigee_client_cert.key - -aws secretsmanager get-secret-value \ - --secret-id ${CLIENT_CERT_ARN} \ - --query SecretString \ - --output text > ${BACKUP_CERTS_DIR}/apigee_client_cert.pem - -aws secretsmanager get-secret-value \ - --secret-id ${CLIENT_SANDBOX_KEY_ARN} \ - --query SecretString \ - --output text > ${BACKUP_KEYS_DIR}/apigee_client_cert_sandbox.key -aws secretsmanager get-secret-value \ - --secret-id ${CLIENT_SANDBOX_CERT_ARN} \ - --query SecretString \ - --output text > ${BACKUP_CERTS_DIR}/apigee_client_cert_sandbox.pem - -echo "Creating new combined truststore files for upload" - -aws s3api head-object --bucket ${TRUSTSTORE_BUCKET_NAME} --key truststore.pem || NOT_EXIST=true -if [ $NOT_EXIST ]; then - echo "" > ${BACKUP_CERTS_DIR}/s3_truststore.pem -else - aws s3 cp s3://${TRUSTSTORE_BUCKET_NAME}/truststore.pem ${BACKUP_CERTS_DIR}/s3_truststore.pem -fi - -aws s3api head-object --bucket ${TRUSTSTORE_BUCKET_NAME} --key sandbox-truststore.pem || NOT_EXIST=true -if [ $NOT_EXIST ]; then - echo "" > ${BACKUP_CERTS_DIR}/s3_sandbox_truststore.pem -else - aws s3 cp s3://${TRUSTSTORE_BUCKET_NAME}/sandbox-truststore.pem ${BACKUP_CERTS_DIR}/s3_sandbox_truststore.pem -fi - - -cat ${BACKUP_CERTS_DIR}/s3_truststore.pem ${CERTS_DIR}/${CA_NAME}.pem > ${CERTS_DIR}/truststore.pem -cat ${BACKUP_CERTS_DIR}/s3_sandbox_truststore.pem ${CERTS_DIR}/${CA_NAME}.pem > ${CERTS_DIR}/sandbox_truststore.pem - - -if [ "$DRY_RUN" = "false" ]; then - echo "Setting new keys in secrets manager" - read -p "Press any key to resume or press ctrl+c to exit ..." - aws secretsmanager put-secret-value \ - --secret-id ${CA_KEY_ARN} \ - --secret-string file://${KEYS_DIR}/${CA_NAME}.key - aws secretsmanager put-secret-value \ - --secret-id ${CA_CERT_ARN} \ - --secret-string file://${CERTS_DIR}/${CA_NAME}.pem - - aws secretsmanager put-secret-value \ - --secret-id ${CLIENT_KEY_ARN} \ - --secret-string file://${KEYS_DIR}/apigee_client_cert.key - aws secretsmanager put-secret-value \ - --secret-id ${CLIENT_CERT_ARN} \ - --secret-string file://${CERTS_DIR}/apigee_client_cert.pem - - aws secretsmanager put-secret-value \ - --secret-id ${CLIENT_SANDBOX_KEY_ARN} \ - --secret-string file://${KEYS_DIR}/apigee_client_cert_sandbox.key - aws secretsmanager put-secret-value \ - --secret-id ${CLIENT_SANDBOX_CERT_ARN} \ - --secret-string file://${CERTS_DIR}/apigee_client_cert_sandbox.pem - - echo "Going to create new truststore files on S3" - read -p "Press any key to resume or press ctrl+c to exit ..." - - aws s3 cp ${CERTS_DIR}/truststore.pem s3://${TRUSTSTORE_BUCKET_NAME}/truststore.pem - aws s3 cp ${CERTS_DIR}/sandbox_truststore.pem s3://${TRUSTSTORE_BUCKET_NAME}/sandbox-truststore.pem - -else - echo "Not setting new secrets or upleading truststore files as dry run set to true" -fi diff --git a/privateCA/openssl-ca.conf b/privateCA/openssl-ca.conf deleted file mode 100644 index babcb329..00000000 --- a/privateCA/openssl-ca.conf +++ /dev/null @@ -1,92 +0,0 @@ -HOME = . -RANDFILE = $ENV::HOME/.rnd - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -[ CA_default ] - -default_days = 3650 # How long to certify for -default_crl_days = 3650 # How long before next CRL -default_md = sha256 # Use public key default MD -preserve = no # Keep passed DN ordering - -x509_extensions = ca_extensions # The extensions to add to the cert - -email_in_dn = no # Don't concat the email in the DN -copy_extensions = copy # Required to copy SANs from CSR to cert - - -base_dir = . -certs = $base_dir/certs # Where the issued certs are kept -crl_dir = $base_dir/crl # Where the issued crl are kept -new_certs_dir = $base_dir/certs # default place for new certs. - -database = $base_dir/config/index.txt # Database index file -serial = $base_dir/config/serial.txt # The current serial number -certificate = $base_dir/certs/ca.pem # The CA certifcate -private_key = $base_dir/private/ca.pem # The CA private key - -crlnumber = $base_dir/config/crlnumber.txt # the current crl number -crl = $base_dir/crl.pem # The current CRL - -unique_subject = no # Set to 'no' to allow creation of - # several certificates with same subject. - -#################################################################### -[ req ] -default_bits = 4096 -default_keyfile = cakey.pem -distinguished_name = ca_distinguished_name -x509_extensions = ca_extensions -string_mask = utf8only - -#################################################################### -[ ca_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = GB - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Leeds - -localityName = Locality Name (eg, city) -localityName_default = Leeds - -organizationName = Organization Name (eg, company) -organizationName_default = nhs - -organizationalUnitName = Organizational Unit (eg, division) -organizationalUnitName_default = clinical tracker private CA - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_default = Prescription Signature Tests - -emailAddress = Email Address -emailAddress_default = anthony.brown8@nhs.net - -#################################################################### -[ ca_extensions ] - -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always, issuer -basicConstraints = critical, CA:true -keyUsage = keyCertSign, cRLSign -crlDistributionPoints = URI:http://crl.nhs.uk/int/1d/arlc3.crl - -#################################################################### -[ signing_policy ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ signing_req ] -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment