From 46d3999f249fda61ad77c41d09a1af740ae0ded8 Mon Sep 17 00:00:00 2001 From: anthony-nhs <121869075+anthony-nhs@users.noreply.github.com> Date: Tue, 24 Mar 2026 09:49:28 +0000 Subject: [PATCH] Chore: [AEA-0000] - new script to create jwks and new prod jwks (#1946) ## Summary - Routine Change ### Details - new script to create jwks - new prod jwks file --- .github/workflows/release.yml | 4 +-- packages/staticContent/jwks/int/jwks.json | 8 +++++ packages/staticContent/jwks/prod/jwks.json | 8 +++++ scripts/create_new_jwks.sh | 40 ++++++++++++++++++++++ scripts/set_secrets.sh | 23 ------------- 5 files changed, 58 insertions(+), 25 deletions(-) create mode 100755 scripts/create_new_jwks.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 423b31b9fb..ae3026efa8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -191,7 +191,7 @@ jobs: APIGEE_PRESCRIPTIONS_ENDPOINT: "https://int.api.service.nhs.uk/clinical-prescription-tracker/" APIGEE_PDS_ENDPOINT: "https://int.api.service.nhs.uk/personal-demographics/FHIR/R4/" APIGEE_DOHS_ENDPOINT: "https://int.api.service.nhs.uk/service-search-api/" - JWT_KID: "eps-cpt-ui-int" + JWT_KID: "eps-cptui-int-2026-03-23" ROLE_ID: "555254242106" LOG_LEVEL: "DEBUG" RUN_REGRESSION_TESTS: false @@ -225,7 +225,7 @@ jobs: APIGEE_PRESCRIPTIONS_ENDPOINT: "https://api.service.nhs.uk/clinical-prescription-tracker/" APIGEE_PDS_ENDPOINT: "https://api.service.nhs.uk/personal-demographics/FHIR/R4/" APIGEE_DOHS_ENDPOINT: "https://api.service.nhs.uk/service-search-api/" - JWT_KID: "eps-cpt-ui-prod" + JWT_KID: "eps-cptui-prod-2026-03-23" ROLE_ID: "555254242106" LOG_LEVEL: "DEBUG" RUN_REGRESSION_TESTS: false diff --git a/packages/staticContent/jwks/int/jwks.json b/packages/staticContent/jwks/int/jwks.json index e286fce032..1bcf877deb 100644 --- a/packages/staticContent/jwks/int/jwks.json +++ b/packages/staticContent/jwks/int/jwks.json @@ -15,6 +15,14 @@ "alg": "RS512", "kid": "eps-cpt-ui-int", "use": "sig" + }, + { + "kty": "RSA", + "n": "uMK5OqjCPb8oz3U3nFDCXHp5K8cm_NG2pzTHjE1Cf-nuKNLnkJgxVOvYamCL9s4IFqMBl6vnJBWe-CjuE0JJa736qmPhX6MvtuVYRxbm6N18s-mhjBvk5EkAXfi5jYTTY75BsqQpvnOFJFDfc5fxHGprYqo0O0xc5CbAXFVf-xrXXNCr5_RaTlreDq7vZhcWHEuI023bAYyH9MHDUx27r6U88VF67lWtvE7ERXxx5f6dBqvNzPDhBXLAFriUHto_41MZ8XD_oG7AktXlFZngBhTgppy6C7TkOvS-8az704fmdr49ZEzKz34FW6GcIslms4oxgvtm2adGrhjnHpZEcw-3TYPCA4-D4GTRJBcStpBgwwE9eRZ_8KPE9IjCzV2f93DVagjA7_Ndq8GFLoKX9Z12wHbJX4rv4XbOvlFmaFEIpqF9nGV3u3WYaNZe_3XTlyVQ_83kyrpB6X7gXDpSTZHN40PekN6MhojoJRrHthrxSktCi155P9yZTWrRZ5hZd1T-0OwSOXeMJ40my823B-Tts7LmbHeD6LX7wd4wc8yMz3eZ5U91hCM2P3Eir_t58kjX53Q9yoAhgxzaj45wBw9OGO8jFsebGsljLZY4TR6Pw_uVRJGovqm3NQamB0Vxetzyj7r5JiNcKOXVUn1ioKJgZyD5bXUaTJVHTk7Xrcs", + "e": "AQAB", + "alg": "RS512", + "kid": "eps-cptui-int-2026-03-23", + "use": "sig" } ] } diff --git a/packages/staticContent/jwks/prod/jwks.json b/packages/staticContent/jwks/prod/jwks.json index e983fca70f..2db4b4b20f 100644 --- a/packages/staticContent/jwks/prod/jwks.json +++ b/packages/staticContent/jwks/prod/jwks.json @@ -7,6 +7,14 @@ "alg": "RS512", "kid": "eps-cpt-ui-prod", "use": "sig" + }, + { + "kty": "RSA", + "n": "sVi07i71VeUejD1uVSsGY-kkinmnz6eoCvfliFhd1v6IWkPfS5cYz4UTS38xCzHPQQRicAoh2hwDlyrQbAXV_8PIzb6ZBg-sdFFeLkHvcHeqb__ldVTrq4zhEZ7Ni1IODvuIUU7QQ_GTHZglH34isi9DD7XPH0P5WlwKdYsQ5TI11lJXMTsjIkC7FzXuyF5_wJe6zJRQtUcTzW2IAZtiRWsWZFv7JGfXDyOH35bcGrHu6htJvOzUx2JTUBP7ws2fy8VvSc6KUkHKMaYyx-Kf9Njq3vswRT-Oqx4b6hJO6xyK4X1aEKQEa7BC0w6FuESbq-OqvEkjaFIaNVu8QHucsMyHtXtBiaFKA2dgwS7UOPDyftnaBzudrlcaz1vJ61Fy7XXxrjqEbbxjax7_sqlq3Eh2xeVnI4iqozqOfISPDwYLZI3TEv1-YTypZ4BUWqqGnvF3kn5G5nr5lz04UvHJsfStBr_j4XwsHHKAEmk3dWywqU51qnfcQt0pWH9mcwR50DuTVgzirkRgIPV-sDtwLhiMNhtHE7dGmDMTIQg8OhD6cNyOXpqPmvDSGCwfxA4NvX74b_nbZbaJ55cIEogqVfYE0nXlNdLWWBFBDEqcYpMB0QsH8dOCNxajv6OrpGzclvSW2sYRkyeHUzGImN8ubAeulfHseGjEoJdLFzxzMws", + "e": "AQAB", + "alg": "RS512", + "kid": "eps-cptui-prod-2026-03-23", + "use": "sig" } ] } diff --git a/scripts/create_new_jwks.sh b/scripts/create_new_jwks.sh new file mode 100755 index 0000000000..7db2e12cd6 --- /dev/null +++ b/scripts/create_new_jwks.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +ENVIRONMENT=${1:?"Usage: $0 "} +CURRENT_DATE=$(date +"%Y-%m-%d") +KID="eps-cptui-${ENVIRONMENT}-${CURRENT_DATE}" +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd) +SECRETS_DIR="$REPO_ROOT/.secrets" +JWKS_FILE="$REPO_ROOT/packages/staticContent/jwks/${ENVIRONMENT}/jwks.json" + +if ! command -v jq >/dev/null 2>&1; then + echo "jq is required to update the JWKS file" >&2 + exit 1 +fi + +if [ ! -f "$JWKS_FILE" ]; then + echo "JWKS file not found for environment '$ENVIRONMENT' at $JWKS_FILE" >&2 + exit 1 +fi + +mkdir -p "$SECRETS_DIR" + +openssl genrsa -out "$SECRETS_DIR/$KID.pem" 4096 +openssl rsa -in "$SECRETS_DIR/$KID.pem" -pubout -outform PEM -out "$SECRETS_DIR/$KID.pem.pub" +MODULUS=$( +openssl rsa -pubin -in "$SECRETS_DIR/$KID.pem.pub" -noout -modulus `# Print modulus of public key` \ +| cut -d '=' -f2 `# Extract modulus value from output` \ +| xxd -r -p `# Convert from string to bytes` \ +| openssl base64 -A `# Base64 encode without wrapping lines` \ +| sed 's|+|-|g; s|/|_|g; s|=||g' `# URL encode as JWK standard requires` +) + +TMP_JWKS=$(mktemp) + +jq --arg n "$MODULUS" \ + --arg kid "$KID" \ + '.keys += [{"kty":"RSA","n":$n,"e":"AQAB","alg":"RS512","kid":$kid,"use":"sig"}]' \ + "$JWKS_FILE" > "$TMP_JWKS" + +mv "$TMP_JWKS" "$JWKS_FILE" diff --git a/scripts/set_secrets.sh b/scripts/set_secrets.sh index d462077ffc..12da592d08 100755 --- a/scripts/set_secrets.sh +++ b/scripts/set_secrets.sh @@ -86,24 +86,11 @@ get_deploy_role() { echo "${CLOUD_FORMATION_DEPLOY_ROLE}" } -get_cdk_image_pull_role() { - environment=$1 - # shellcheck disable=SC2016 - CDK_PULL_IMAGE_ROLE=$(aws cloudformation list-exports \ - --profile prescription-"${environment}" \ - --query 'Exports[?Name==`ci-resources:CDKPullImageRole`].Value' \ - --output text) - - echo "${CDK_PULL_IMAGE_ROLE}" -} - check_gh_logged_in # dev and dev-pr DEV_DEPLOY_ROLE=$(get_deploy_role dev) -DEV_CDK_PULL_IMAGE_ROLE=$(get_cdk_image_pull_role dev) -set_environment_secret CDK_PULL_IMAGE_ROLE "${DEV_CDK_PULL_IMAGE_ROLE}" dev-pr set_environment_secret CLOUD_FORMATION_DEPLOY_ROLE "${DEV_DEPLOY_ROLE}" dev-pr set_environment_secret CIS2_OIDC_CLIENT_ID "${DEV_CIS2_OIDC_CLIENT_ID}" dev-pr set_environment_secret MOCK_OIDC_CLIENT_ID "${DEV_MOCK_CLIENT_ID}" dev-pr @@ -114,7 +101,6 @@ set_environment_secret APIGEE_DOHS_API_KEY "${APIGEE_PTL_DOHS_API_KEY}" dev-pr set_environment_secret CLOUDFRONT_ORIGIN_CUSTOM_HEADER "$(uuidgen)" dev-pr set_environment_private_key_secret REGRESSION_TESTS_PEM ".secrets/eps-regression-testing.private-key.pem" dev-pr -set_repository_secret CDK_PULL_IMAGE_ROLE "${DEV_CDK_PULL_IMAGE_ROLE}" dependabot set_repository_secret CLOUD_FORMATION_DEPLOY_ROLE "${DEV_DEPLOY_ROLE}" dependabot set_repository_secret CIS2_OIDC_CLIENT_ID "${DEV_CIS2_OIDC_CLIENT_ID}" dependabot set_repository_secret MOCK_OIDC_CLIENT_ID "${DEV_MOCK_CLIENT_ID}" dependabot @@ -125,7 +111,6 @@ set_repository_secret APIGEE_DOHS_API_KEY "${APIGEE_PTL_DOHS_API_KEY}" dependabo set_repository_secret CLOUDFRONT_ORIGIN_CUSTOM_HEADER "$(uuidgen)" dependabot set_repository_private_key_secret REGRESSION_TESTS_PEM ".secrets/eps-regression-testing.private-key.pem" dependabot -set_environment_secret CDK_PULL_IMAGE_ROLE "${DEV_CDK_PULL_IMAGE_ROLE}" dev set_environment_secret CLOUD_FORMATION_DEPLOY_ROLE "${DEV_DEPLOY_ROLE}" dev set_environment_secret CIS2_OIDC_CLIENT_ID "${DEV_CIS2_OIDC_CLIENT_ID}" dev set_environment_secret MOCK_OIDC_CLIENT_ID "${DEV_MOCK_CLIENT_ID}" dev @@ -137,8 +122,6 @@ set_environment_secret CLOUDFRONT_ORIGIN_CUSTOM_HEADER "$(uuidgen)" dev set_environment_private_key_secret REGRESSION_TESTS_PEM ".secrets/eps-regression-testing.private-key.pem" dev QA_DEPLOY_ROLE=$(get_deploy_role qa) -QA_CDK_PULL_IMAGE_ROLE=$(get_cdk_image_pull_role qa) -set_environment_secret CDK_PULL_IMAGE_ROLE "${QA_CDK_PULL_IMAGE_ROLE}" qa set_environment_secret CLOUD_FORMATION_DEPLOY_ROLE "${QA_DEPLOY_ROLE}" qa set_environment_secret CIS2_OIDC_CLIENT_ID "${QA_CIS2_OIDC_CLIENT_ID}" qa set_environment_secret MOCK_OIDC_CLIENT_ID "${QA_MOCK_CLIENT_ID}" qa @@ -150,8 +133,6 @@ set_environment_secret CLOUDFRONT_ORIGIN_CUSTOM_HEADER "$(uuidgen)" qa set_environment_private_key_secret REGRESSION_TESTS_PEM ".secrets/eps-regression-testing.private-key.pem" qa REF_DEPLOY_ROLE=$(get_deploy_role ref) -REF_CDK_PULL_IMAGE_ROLE=$(get_cdk_image_pull_role ref) -set_environment_secret CDK_PULL_IMAGE_ROLE "${REF_CDK_PULL_IMAGE_ROLE}" ref set_environment_secret CLOUD_FORMATION_DEPLOY_ROLE "${REF_DEPLOY_ROLE}" ref set_environment_secret CIS2_OIDC_CLIENT_ID "${QA_CIS2_OIDC_CLIENT_ID}" ref set_environment_secret MOCK_OIDC_CLIENT_ID "${QA_MOCK_CLIENT_ID}" ref @@ -163,8 +144,6 @@ set_environment_secret CLOUDFRONT_ORIGIN_CUSTOM_HEADER "$(uuidgen)" ref set_environment_private_key_secret REGRESSION_TESTS_PEM ".secrets/eps-regression-testing.private-key.pem" ref INT_DEPLOY_ROLE=$(get_deploy_role int) -INT_CDK_PULL_IMAGE_ROLE=$(get_cdk_image_pull_role int) -set_environment_secret CDK_PULL_IMAGE_ROLE "${INT_CDK_PULL_IMAGE_ROLE}" int set_environment_secret CLOUD_FORMATION_DEPLOY_ROLE "${INT_DEPLOY_ROLE}" int set_environment_secret CIS2_OIDC_CLIENT_ID "${INT_CIS2_OIDC_CLIENT_ID}" int set_environment_secret MOCK_OIDC_CLIENT_ID "${INT_MOCK_CLIENT_ID}" int @@ -176,8 +155,6 @@ set_environment_secret CLOUDFRONT_ORIGIN_CUSTOM_HEADER "$(uuidgen)" int set_environment_private_key_secret REGRESSION_TESTS_PEM ".secrets/eps-regression-testing.private-key.pem" int PROD_DEPLOY_ROLE=$(get_deploy_role prod) -PROD_CDK_PULL_IMAGE_ROLE=$(get_cdk_image_pull_role prod) -set_environment_secret CDK_PULL_IMAGE_ROLE "${PROD_CDK_PULL_IMAGE_ROLE}" prod set_environment_secret CLOUD_FORMATION_DEPLOY_ROLE "${PROD_DEPLOY_ROLE}" prod set_environment_secret CIS2_OIDC_CLIENT_ID "${PROD_CIS2_OIDC_CLIENT_ID}" prod set_environment_secret MOCK_OIDC_CLIENT_ID "${PROD_MOCK_CLIENT_ID}" prod