Skip to content

Commit

Permalink
Update: [AEA-3859] - Create Apigee proxy for PSU API (#99)
Browse files Browse the repository at this point in the history
## Summary

🎫 [AEA-3859](https://nhsd-jira.digital.nhs.uk/browse/AEA-3859) Create
Apigee proxy for PSU API

- ❗ Breaking Change
- 🤖 Operational or Infrastructure Change
- ✨ New Feature
- ⚠️ Potential issues that might be caused by this change

### Details

This pull request encompasses the creation of the Apigee proxy for the
PSU API. This should be executed using Proxygen, employing an
application-restricted authentication model, and interfacing with the
PSU AWS API.
  • Loading branch information
kris-szlapa authored Apr 17, 2024
1 parent d25e910 commit b40beaf
Show file tree
Hide file tree
Showing 23 changed files with 1,091 additions and 260 deletions.
97 changes: 97 additions & 0 deletions .github/scripts/deploy_api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env bash

echo "Proxygen path: $PROXYGEN_PATH"
echo "Specification path: $SPEC_PATH"
echo "Specification version: $VERSION_NUMBER"
echo "Stack name: $STACK_NAME"
echo "Target environment: $TARGET_ENVIRONMENT"

# Extract the AWS environment name from the target environment
aws_environment=$(echo "$TARGET_ENVIRONMENT" | cut -d'-' -f1)
echo "AWS environment: $aws_environment"

# Determine the proxy environment based on the target environment
case "$TARGET_ENVIRONMENT" in
dev-pr|dev)
environment=internal-dev
;;
qa)
environment=internal-qa
;;
*)
environment=$TARGET_ENVIRONMENT
;;
esac
echo "Proxy environment: $environment"

# Determine the proxy instance based on the provided $STACK_NAME
case "$STACK_NAME" in
psu)
instance=prescription-status-update
;;
psu-pr-*)
if [[ $STACK_NAME == psu-pr-* ]]; then
# Extracting the PR ID from $STACK_NAME
pr_id=$(echo "$STACK_NAME" | cut -d'-' -f3)
# Check if it's a sandbox environment
if [[ $STACK_NAME == *sandbox ]]; then
instance=prescription-status-update-pr-$pr_id-sandbox
else
instance=prescription-status-update-pr-$pr_id
fi
fi
;;
*)
instance=$STACK_NAME
;;
esac
echo "Proxy instance: $instance"

# Find and replace the specification version number
jq --arg version "$VERSION_NUMBER" '.info.version = $version' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH"

# Find and replace the x-nhsd-apim.target.url value
jq --arg stack_name "$STACK_NAME" --arg aws_env "$aws_environment" '.["x-nhsd-apim"].target.url = "https://\($stack_name).\($aws_env).eps.national.nhs.uk"' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH"

# Find and replace the servers object
jq --arg env "$environment" --arg inst "$instance" '.servers = [ { "url": "https://\($env).api.service.nhs.uk/\($inst)" } ]' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH"

# 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:ProxgenPrivateKey'].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

# Create credentials.yaml file
cat <<EOF > ~/.proxygen/credentials.yaml
client_id: prescription-status-update-api-client
key_id: eps-cli-key-1
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/prescription-status-update-api.json
EOF

# Create settings.yaml file
cat <<EOF > ~/.proxygen/settings.yaml
api: prescription-status-update-api
endpoint_url: https://proxygen.prod.api.platform.nhs.uk
spec_output_format: json
EOF


# Store the API key secret using Proxygen CLI
"$PROXYGEN_PATH" secret put --mtls-cert ~/.proxygen/tmp/client_cert.pem --mtls-key ~/.proxygen/tmp/client_private_key.pem "$environment" psu-mtls-1

# Deploy the API instance using Proxygen CLI
"$PROXYGEN_PATH" instance deploy --no-confirm "$environment" "$instance" "$SPEC_PATH"
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ jobs:
TARGET_ENVIRONMENT: dev
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}}
COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}}
Expand All @@ -116,6 +117,7 @@ jobs:
TARGET_ENVIRONMENT: qa
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}}
COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}}
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ jobs:
TARGET_ENVIRONMENT: dev-pr
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: PR-${{ needs.get_issue_number.outputs.issue_number }}
COMMIT_ID: ${{ needs.get_commit_id.outputs.commit_id }}
Expand All @@ -83,6 +84,7 @@ jobs:
TARGET_ENVIRONMENT: dev-pr
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_sandbox_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-sandbox-truststore.pem
VERSION_NUMBER: PR-${{ needs.get_issue_number.outputs.issue_number }}
COMMIT_ID: ${{ needs.get_commit_id.outputs.commit_id }}
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ jobs:
TARGET_ENVIRONMENT: dev
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}}
COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}}
Expand All @@ -142,6 +143,7 @@ jobs:
TARGET_ENVIRONMENT: ref
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}}
COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}}
Expand All @@ -159,6 +161,7 @@ jobs:
TARGET_ENVIRONMENT: qa
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}}
COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}}
Expand All @@ -176,6 +179,7 @@ jobs:
TARGET_ENVIRONMENT: int
ENABLE_MUTUAL_TLS: false
BUILD_ARTIFACT: packaged_code
SPEC_ARTIFACT: specification_code
TRUSTSTORE_FILE: psu-truststore.pem
VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}}
COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}}
Expand Down
22 changes: 16 additions & 6 deletions .github/workflows/sam_package_code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,40 @@ jobs:
echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc
echo "@nhsdigital:registry=https://npm.pkg.github.com" >> ~/.npmrc
- name: make install
- name: Run make install
run: |
make install
- shell: bash
name: package code
name: Package code
run: |
cp .tool-versions ~/
rm -rf .aws-sam
export PATH=$PATH:$PWD/node_modules/.bin
make publish
make sam-build
cp Makefile .aws-sam/build/
cp samconfig_package_and_deploy.toml .aws-sam/build/
mkdir -p .aws-sam/build/specification
cp packages/specification/dist/eps-prescription-status-update-api.resolved.json .aws-sam/build/specification/
- uses: actions/upload-artifact@v4
name: upload build artifact
name: Upload build artifact
with:
name: packaged_code
path: |
.aws-sam/build
SAMtemplates/state_machines/UpdatePrescriptionStatusStateMachine.asl.json
- uses: actions/upload-artifact@v4
name: Upload specification artifact
with:
name: specification_code
path: |
.aws-sam/build/specification
- shell: bash
name: package sandbox
name: Package sandbox
run: |
cp .tool-versions ~/
rm -rf .aws-sam
Expand All @@ -79,9 +89,9 @@ jobs:
# Readme is included to stop the action flattening the folder structure of aws-sam/build when it is the only item to upload
- uses: actions/upload-artifact@v4
name: upload sandbox build artifact
name: Upload sandbox build artifact
with:
name: packaged_sandbox_code
path: |
.aws-sam/build
README.md
README.md
40 changes: 38 additions & 2 deletions .github/workflows/sam_release_code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ on:
BUILD_ARTIFACT:
required: true
type: string
SPEC_ARTIFACT:
required: true
type: string
TRUSTSTORE_FILE:
required: true
type: string
Expand Down Expand Up @@ -94,12 +97,34 @@ jobs:
role-to-assume: ${{ secrets.CLOUD_FORMATION_DEPLOY_ROLE }}
role-session-name: github-actions

- name: download build artifact
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.BUILD_ARTIFACT }}
path: .

- name: Download specification artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.SPEC_ARTIFACT }}
path: .

- name: Install proxygen-cli
run: |
pip install proxygen-cli
- name: Export specification path
run: |
SPEC_PATH="$(pwd)/eps-prescription-status-update-api.resolved.json"
echo "Specification location: $SPEC_PATH"
echo "SPEC_PATH=${SPEC_PATH}" >> "$GITHUB_ENV"
- name: Export proxygen path
run: |
PROXYGEN_PATH=$(which proxygen)
echo "Proxygen location: $PROXYGEN_PATH"
echo "PROXYGEN_PATH=${PROXYGEN_PATH}" >> "$GITHUB_ENV"
- name: release code
shell: bash
working-directory: .github/scripts
Expand All @@ -116,6 +141,17 @@ jobs:
VERSION_NUMBER: ${{ inputs.VERSION_NUMBER }}
run: ./release_code.sh

- name: Deploy API
shell: bash
working-directory: .github/scripts
env:
VERSION_NUMBER: ${{ inputs.VERSION_NUMBER }}
PROXYGEN_PATH: ${{ env.PROXYGEN_PATH }}
SPEC_PATH: ${{ env.SPEC_PATH }}
STACK_NAME: ${{ inputs.STACK_NAME }}
TARGET_ENVIRONMENT: ${{ inputs.TARGET_ENVIRONMENT }}
run: ./deploy_api.sh

- name: create_int_release_notes
uses: ./.github/actions/update_confluence_jira
if: ${{ inputs.CREATE_INT_RELEASE_NOTES == true && always() && !failure() && !cancelled() }}
Expand Down Expand Up @@ -151,7 +187,7 @@ jobs:
ref: gh-pages
path: gh-pages

- name: update release tag in github pages
- name: Update release tag in github pages
if: ${{ inputs.TARGET_ENVIRONMENT != 'dev-pr' }}
run: |
cd gh-pages
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
nodejs 20.10.0
python 3.12.2
poetry 1.6.1
poetry 1.8.2
shellcheck 0.9.0
direnv 2.32.2
actionlint 1.6.26
Expand Down
3 changes: 1 addition & 2 deletions .vscode/eps-prescription-status-update-api.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
],
"settings": {
"jest.disabledWorkspaceFolders": [
"eps-prescription-status-update-monorepo",
"packages/specification",
"eps-prescription-status-update-monorepo"
],
"files.exclude": {
"packages/": true,
Expand Down
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ guard-%:

install: install-node install-python install-hooks

#Installs dependencies using poetry.
install-python:
poetry install

#Installs dependencies using npm.
install-node:
npm install --legacy-peer-deps

Expand Down Expand Up @@ -123,23 +121,26 @@ lint: lint-node lint-samtemplates lint-python lint-githubactions lint-githubacti
test: compile
npm run test --workspace packages/updatePrescriptionStatus
npm run test --workspace packages/sandbox
npm run test --workspace packages/specification

#Removes build/ + dist/ directories
clean:
rm -rf packages/updatePrescriptionStatus/coverage
rm -rf packages/updatePrescriptionStatus/lib
rm -rf packages/sandbox/coverage
rm -rf packages/sandbox/lib
rm -rf packages/specification/coverage
rm -rf packages/specification/lib
rm -rf .aws-sam

deep-clean: clean
rm -rf venv
find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +
poetry env remove --all

#Creates the fully expanded OAS spec in json
publish:
npm run resolve --workspace packages/specification 2> /dev/null
npm run compile --workspace packages/specification 2> /dev/null
npm run replace-components --workspace packages/specification 2> /dev/null

check-licenses: check-licenses-node check-licenses-python

Expand Down
31 changes: 31 additions & 0 deletions packages/specification/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"name": "vscode-jest-tests.v2",
"request": "launch",
"args": [
"--runInBand",
"--watchAll=false",
"--testNamePattern",
"${jest.testNamePattern}",
"--runTestsByPath",
"${jest.testFile}",
"--config",
"${workspaceFolder}/jest.debug.config.ts"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"program": "${workspaceFolder}/../../node_modules/.bin/jest",
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
},
"env": {
"POWERTOOLS_DEV": "true",
"NODE_OPTIONS": "--experimental-vm-modules"
}
}
]
}
7 changes: 7 additions & 0 deletions packages/specification/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"jest.jestCommandLine": "/workspaces/eps-prescription-status-update-api/node_modules/.bin/jest --no-cache",
"jest.nodeEnv": {
"POWERTOOLS_DEV": true,
"NODE_OPTIONS": "--experimental-vm-modules"
}
}
Loading

0 comments on commit b40beaf

Please sign in to comment.