Skip to content

Commit

Permalink
Fix: [AEA-4261] - use proxygen lambdas for proxygen work (#559)
Browse files Browse the repository at this point in the history
## Summary

- Routine Change

### Details

- use proxygen lambdas to set MTLS secret 
- use proxygen lamda to create/update api in apigee 
- use proxygen lambda to create/update spec
- use proxygen lambda delete_old_cloudformation_stacks.sh to get stacks
- use proxygen lambda delete_old_cloudformation_stacks.sh to delete
stacks
- use a separate script for deleting cloudformation stacks and proxygen
deployments as they use different AWS credentials
  • Loading branch information
anthony-nhs committed Aug 7, 2024
1 parent a73294b commit e4205b3
Show file tree
Hide file tree
Showing 12 changed files with 695 additions and 784 deletions.
76 changes: 76 additions & 0 deletions .github/scripts/delete_proxygen_deployments.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash

# generic script for removing cloudformation stacks and proxygen deployed apis where the pull request is closed

# set the repo name to be the name of the repo this is running in
REPO_NAME=eps-prescription-status-update-api

# this should be customised to delete cloudformation stacks and proxygen deployments if they are used
main() {
echo "Checking prescripton status update deployments"
PULL_REQUEST_PROXYGEN_REGEX=prescription-status-update-pr-
delete_apigee_deployments "internal-dev" "prescription-status-update-api" "PSUProxygenPrivateKey" "eps-cli-key-1"
delete_apigee_deployments "internal-dev-sandbox" "prescription-status-update-api" "PSUProxygenPrivateKey" "eps-cli-key-1"

echo "Checking custom prescripton status update deployments"
PULL_REQUEST_PROXYGEN_REGEX=custom-prescription-status-update-pr-
delete_apigee_deployments "internal-dev" "custom-prescription-status-update-api" "CPSUProxygenPrivateKey" "eps-cli-key-cpsu-1"
delete_apigee_deployments "internal-dev-sandbox" "custom-prescription-status-update-api" "CPSUProxygenPrivateKey" "eps-cli-key-cpsu-1"
}

delete_apigee_deployments() {
APIGEE_ENVIRONMENT=$1
APIGEE_API=$2
PROXYGEN_PRIVATE_KEY_NAME=$3
PROXYGEN_KID=$4
proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:${PROXYGEN_PRIVATE_KEY_NAME}'].Value" --output text)

echo
echo "checking apigee deployments on ${APIGEE_ENVIRONMENT}"
echo

jq -n --arg apiName "${APIGEE_API}" \
--arg environment "${APIGEE_ENVIRONMENT}" \
--arg kid "${PROXYGEN_KID}" \
--arg proxygenSecretName "${proxygen_private_key_arn}" \
'{apiName: $apiName, environment: $environment, kid, $kid, proxygenSecretName: $proxygenSecretName}' > payload.json

aws lambda invoke --function-name "lambda-resources-ProxygenPTLInstanceGet" --cli-binary-format raw-in-base64-out --payload file://payload.json out.json > response.json

if eval "cat response.json | jq -e '.FunctionError' >/dev/null"; then
echo 'Error calling lambda'
cat out.json
exit 1
fi

jq -r '.[].name' "out.json" | while read -r i; do
echo "Checking if apigee deployment $i has open pull request"
PULL_REQUEST=${i//${PULL_REQUEST_PROXYGEN_REGEX}/}
echo "Checking pull request id ${PULL_REQUEST}"
URL="https://api.github.com/repos/NHSDigital/${REPO_NAME}/pulls/${PULL_REQUEST}"
RESPONSE=$(curl "${URL}" 2>/dev/null)
STATE=$(echo "${RESPONSE}" | jq -r .state)
if [ "$STATE" == "closed" ]; then
echo "** going to delete apigee deployment $i as state is ${STATE} **"
jq -n --arg apiName "${APIGEE_API}" \
--arg environment "${APIGEE_ENVIRONMENT}" \
--arg instance "${i}" \
--arg kid "${PROXYGEN_KID}" \
--arg proxygenSecretName "${proxygen_private_key_arn}" \
'{apiName: $apiName, environment: $environment, kid, $kid, proxygenSecretName: $proxygenSecretName, instance: $instance}' > payload.json

aws lambda invoke --function-name "lambda-resources-ProxygenPTLInstanceDelete" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt > response.json
if eval "cat response.json | jq -e '.FunctionError' >/dev/null"; then
echo 'Error calling lambda'
cat out.txt
exit 1
fi


else
echo "not going to delete apigee deployment $i as state is ${STATE}"
fi
done
}

main
74 changes: 0 additions & 74 deletions .github/scripts/delete_stacks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,10 @@ CAPTURE_REGEX="^psu-pr-(\\d+)(-sandbox)?$"
# this is used in a replace command to replace the stack name so what is left is just the pull request id
PULL_REQUEST_STACK_REGEX=psu-pr-

# this should be a regex that is used to get the pull request id from the proxygen deployed API
# this is used in a replace command to replace the proxy name so what is left is just the pull request id
PULL_REQUEST_PROXYGEN_REGEX=prescription-status-update-pr-

# this should be customised to delete cloudformation stacks and proxygen deployments if they are used
main() {
delete_cloudformation_stacks
create_proxygen_credentials "PSUProxygenPrivateKey" "eps-cli-key-1" "prescription-status-update-api"
delete_apigee_deployments "internal-dev"
delete_apigee_deployments "internal-dev-sandbox"

PULL_REQUEST_PROXYGEN_REGEX=custom-prescription-status-update-pr-
create_proxygen_credentials "CPSUProxygenPrivateKey" "eps-cli-key-cpsu-1" "custom-prescription-status-update-api"
delete_apigee_deployments "internal-dev"
delete_apigee_deployments "internal-dev-sandbox"
}

delete_cloudformation_stacks() {
Expand Down Expand Up @@ -56,68 +45,5 @@ delete_cloudformation_stacks() {
done
}

create_proxygen_credentials() {
PROXYGEN_PRIVATE_KEY_NAME=$1
PROXYGEN_KID=$2
APIGEE_API=$3
echo
echo "getting proxygen key"
echo "PROXYGEN_PRIVATE_KEY_NAME: ${PROXYGEN_PRIVATE_KEY_NAME}"
echo "PROXYGEN_KID: ${PROXYGEN_KID}"
echo "APIGEE_API: ${APIGEE_API}"
echo
# Retrieve the proxygen private key
proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:${PROXYGEN_PRIVATE_KEY_NAME}'].Value" --output text)
proxygen_private_key=$(aws secretsmanager get-secret-value --secret-id "${proxygen_private_key_arn}" --query SecretString --output text)

# Create the .proxygen/tmp directory if it doesn't exist
mkdir -p ~/.proxygen/tmp

# Save the proxygen private key, client private key, and client cert to temporary files
echo "$proxygen_private_key" > ~/.proxygen/tmp/proxygen_private_key.pem

# Create the .proxygen/tmp directory if it doesn't exist
mkdir -p ~/.proxygen/tmp
# Create credentials.yaml file
cat <<EOF > ~/.proxygen/credentials.yaml
client_id: ${APIGEE_API}-client
key_id: ${PROXYGEN_KID}
private_key_path: tmp/proxygen_private_key.pem
base_url: https://identity.prod.api.platform.nhs.uk/realms/api-producers
client_secret: https://nhsdigital.github.io/identity-service-jwks/jwks/paas/${APIGEE_API}.json
EOF

# Create settings.yaml file
cat <<EOF > ~/.proxygen/settings.yaml
api: ${APIGEE_API}
endpoint_url: https://proxygen.prod.api.platform.nhs.uk
spec_output_format: json
EOF
}

delete_apigee_deployments() {
APIGEE_ENVIRONMENT=$1
echo
echo "checking apigee deployments on ${APIGEE_ENVIRONMENT}"
echo
ACTIVE_APIGEE=$(poetry run proxygen instance list --env "${APIGEE_ENVIRONMENT}" | awk 'NR > 2 {print $3}')
mapfile -t ACTIVE_APIGEE_ARRAY <<< "$ACTIVE_APIGEE"

for i in "${ACTIVE_APIGEE_ARRAY[@]}"
do
echo "Checking if apigee deployment $i has open pull request"
PULL_REQUEST=${i//${PULL_REQUEST_PROXYGEN_REGEX}/}
echo "Checking pull request id ${PULL_REQUEST}"
URL="https://api.github.com/repos/NHSDigital/${REPO_NAME}/pulls/${PULL_REQUEST}"
RESPONSE=$(curl "${URL}" 2>/dev/null)
STATE=$(echo "${RESPONSE}" | jq -r .state)
if [ "$STATE" == "closed" ]; then
echo "** going to delete apigee deployment $i as state is ${STATE} **"
poetry run proxygen instance delete --no-confirm "${APIGEE_ENVIRONMENT}" "${i}"
else
echo "not going to delete apigee deployment $i as state is ${STATE}"
fi
done
}

main
126 changes: 82 additions & 44 deletions .github/scripts/deploy_api.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
set -eu pipefail

echo "API type: ${API_TYPE}"
echo "Proxygen path: ${PROXYGEN_PATH}"
echo "Specification path: ${SPEC_PATH}"
echo "Specification version: ${VERSION_NUMBER}"
echo "Stack name: ${STACK_NAME}"
Expand All @@ -13,6 +12,30 @@ echo "Proxygen KID: ${PROXYGEN_KID}"
echo "Deploy Check Prescription Status Update: ${DEPLOY_CHECK_PRESCRIPTION_STATUS_UPDATE}"
echo "Dry run: ${DRY_RUN}"


client_private_key=$(cat ~/.proxygen/tmp/client_private_key)
client_cert=$(cat ~/.proxygen/tmp/client_cert)

if [ -z "${client_private_key}" ]; then
echo "client_private_key is unset or set to the empty string"
exit 1
fi
if [ -z "${client_cert}" ]; then
echo "client_cert is unset or set to the empty string"
exit 1
fi

put_secret_lambda=lambda-resources-ProxygenPTLMTLSSecretPut
instance_put_lambda=lambda-resources-ProxygenPTLInstancePut
spec_publish_lambda=lambda-resources-ProxygenPTLSpecPublish

if [[ "$APIGEE_ENVIRONMENT" =~ ^(int|sandbox|prod)$ ]]; then
put_secret_lambda=lambda-resources-ProxygenProdMTLSSecretPut
instance_put_lambda=lambda-resources-ProxygenProdInstancePut
spec_publish_lambda=lambda-resources-ProxygenProdSpecPublish
fi


is_pull_request=false
instance_suffix=""
if [[ ${STACK_NAME} == psu-pr-* ]]; then
Expand Down Expand Up @@ -94,74 +117,89 @@ echo "Retrieving proxygen credentials"

# Retrieve the proxygen private key and client private key and cert from AWS Secrets Manager
proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:${PROXYGEN_PRIVATE_KEY_NAME}'].Value" --output text)
client_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:PsuClientKeySecret'].Value" --output text)
client_cert_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:PsuClientCertSecret'].Value" --output text)

proxygen_private_key=$(aws secretsmanager get-secret-value --secret-id "${proxygen_private_key_arn}" --query SecretString --output text)
client_private_key=$(aws secretsmanager get-secret-value --secret-id "${client_private_key_arn}" --query SecretString --output text)
client_cert=$(aws secretsmanager get-secret-value --secret-id "${client_cert_arn}" --query SecretString --output text)

# Create the .proxygen/tmp directory if it doesn't exist
mkdir -p ~/.proxygen/tmp

# Save the proxygen private key, client private key, and client cert to temporary files
echo "${proxygen_private_key}" > ~/.proxygen/tmp/proxygen_private_key.pem
echo "${client_private_key}" > ~/.proxygen/tmp/client_private_key.pem
echo "${client_cert}" > ~/.proxygen/tmp/client_cert.pem

cat <<EOF > ~/.proxygen/credentials.yaml
client_id: ${apigee_api}-client
key_id: ${PROXYGEN_KID}
private_key_path: tmp/proxygen_private_key.pem
base_url: https://identity.prod.api.platform.nhs.uk/realms/api-producers
client_secret: https://nhsdigital.github.io/identity-service-jwks/jwks/paas/${apigee_api}.json
EOF

# Create settings.yaml file
cat <<EOF > ~/.proxygen/settings.yaml
api: ${apigee_api}
endpoint_url: https://proxygen.prod.api.platform.nhs.uk
spec_output_format: json
EOF

if [[ "${is_pull_request}" == "false" ]]; then
echo
echo "Store the secret used for mutual TLS to AWS using Proxygen CLI"
echo "Store the secret used for mutual TLS to AWS using Proxygen proxy lambda"
if [[ "${DRY_RUN}" == "false" ]]; then
"${PROXYGEN_PATH}" secret put --mtls-cert ~/.proxygen/tmp/client_cert.pem --mtls-key ~/.proxygen/tmp/client_private_key.pem "${APIGEE_ENVIRONMENT}" psu-mtls-1
jq -n --arg apiName "${apigee_api}" \
--arg environment "${APIGEE_ENVIRONMENT}" \
--arg secretName "psu-mtls-1" \
--arg secretKey "${client_private_key}" \
--arg secretCert "${client_cert}" \
--arg kid "${PROXYGEN_KID}" \
--arg proxygenSecretName "${proxygen_private_key_arn}" \
'{apiName: $apiName, environment: $environment, secretName: $secretName, secretKey: $secretKey, secretCert: $secretCert, kid, $kid, proxygenSecretName: $proxygenSecretName}' > payload.json

aws lambda invoke --function-name "${put_secret_lambda}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt > response.json
if eval "cat response.json | jq -e '.FunctionError' >/dev/null"; then
echo 'Error calling lambda'
cat out.txt
exit 1
fi
echo "Secret stored succesfully"

else
echo "Would run this command"
echo "${PROXYGEN_PATH} secret put --mtls-cert ~/.proxygen/tmp/client_cert.pem --mtls-key ~/.proxygen/tmp/client_private_key.pem ${APIGEE_ENVIRONMENT} psu-mtls-1"
echo "Would call ${put_secret_lambda}"
fi
fi

echo
echo "Deploy the API instance using Proxygen CLI"
echo "Deploy the API instance using Proxygen proxy lambda"
if [[ "${DRY_RUN}" == "false" ]]; then
"${PROXYGEN_PATH}" instance deploy --no-confirm "${APIGEE_ENVIRONMENT}" "${instance}" "${SPEC_PATH}"

jq -n --argfile spec "${SPEC_PATH}" \
--arg apiName "${apigee_api}" \
--arg environment "${APIGEE_ENVIRONMENT}" \
--arg instance "${instance}" \
--arg kid "${PROXYGEN_KID}" \
--arg proxygenSecretName "${proxygen_private_key_arn}" \
'{apiName: $apiName, environment: $environment, specDefinition: $spec, instance: $instance, kid: $kid, proxygenSecretName: $proxygenSecretName}' > payload.json

aws lambda invoke --function-name "${instance_put_lambda}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt > response.json

if eval "cat response.json | jq -e '.FunctionError' >/dev/null"; then
echo 'Error calling lambda'
cat out.txt
exit 1
fi
echo "Instance deployed"
else
echo "Would run this command"
echo "${PROXYGEN_PATH} instance deploy --no-confirm ${APIGEE_ENVIRONMENT} ${instance} ${SPEC_PATH}"
echo "Would call ${instance_put_lambda}"
fi

if [[ "${APIGEE_ENVIRONMENT}" == "int" ]]; then
echo
echo "Deploy the API spec if in the int environment"
if [[ "${DRY_RUN}" == "false" ]]; then
"${PROXYGEN_PATH}" spec publish --no-confirm "${SPEC_PATH}"
jq -n --argfile spec "${SPEC_PATH}" \
--arg apiName "${apigee_api}" \
--arg environment "uat" \
--arg instance "${instance}" \
--arg kid "${PROXYGEN_KID}" \
--arg proxygenSecretName "${proxygen_private_key_arn}" \
'{apiName: $apiName, environment: $environment, specDefinition: $spec, instance: $instance, kid: $kid, proxygenSecretName: $proxygenSecretName}' > payload.json

aws lambda invoke --function-name "${spec_publish_lambda}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt > response.json
else
echo "Would run this command"
echo "${PROXYGEN_PATH} spec publish --no-confirm ${SPEC_PATH}"
echo "Would call ${spec_publish_lambda}"
fi
fi

if [[ "${APIGEE_ENVIRONMENT}" == "internal-dev" && "${is_pull_request}" == "false" ]]; then
echo
echo "Deploy the API spec to uat if in the internal-dev environment"
if [[ "${DRY_RUN}" == "false" ]]; then
"${PROXYGEN_PATH}" spec publish --uat --no-confirm "${SPEC_PATH}"
jq -n --argfile spec "${SPEC_PATH}" \
--arg apiName "${apigee_api}" \
--arg environment "uat" \
--arg instance "${instance}" \
--arg kid "${PROXYGEN_KID}" \
--arg proxygenSecretName "${proxygen_private_key_arn}" \
'{apiName: $apiName, environment: $environment, specDefinition: $spec, instance: $instance, kid: $kid, proxygenSecretName: $proxygenSecretName}' > payload.json

aws lambda invoke --function-name "${spec_publish_lambda}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt > response.json
else
echo "Would run this command"
echo "${PROXYGEN_PATH} spec publish --uat --no-confirm ${SPEC_PATH}"
echo "Would call ${spec_publish_lambda}"
fi
fi
Loading

0 comments on commit e4205b3

Please sign in to comment.