diff --git a/.gitignore b/.gitignore index 0bce0b40..75eae505 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,7 @@ terraform.tfstate* .terraform* # Local blob storage data -/localdata +/localdata/data # Items added by creating the Azure function: diff --git a/.secrets.baseline b/.secrets.baseline index 66e60883..ebcab454 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -90,6 +90,10 @@ { "path": "detect_secrets.filters.allowlist.is_line_allowlisted" }, + { + "path": "detect_secrets.filters.common.is_baseline_file", + "filename": ".secrets.baseline" + }, { "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", "min_level": 2 @@ -122,6 +126,103 @@ "path": "detect_secrets.filters.heuristic.is_templated_secret" } ], - "results": {}, - "generated_at": "2024-05-15T17:31:59Z" + "results": { + ".github/workflows/prod-deploy.yml": [ + { + "type": "Secret Keyword", + "filename": ".github/workflows/prod-deploy.yml", + "hashed_secret": "3e26d6750975d678acb8fa35a0f69237881576b0", + "is_verified": false, + "line_number": 12, + "is_secret": false + } + ], + "SECRETS.md": [ + { + "type": "Secret Keyword", + "filename": "SECRETS.md", + "hashed_secret": "4ea048262c33345f67eb41df9f916812bf143cc4", + "is_verified": false, + "line_number": 11, + "is_secret": false + } + ], + "azure_functions/local.settings.json": [ + { + "type": "Azure Storage Account access key", + "filename": "azure_functions/local.settings.json", + "hashed_secret": "5666459779d6a76bea73453137803fd27d8f79cd", + "is_verified": false, + "line_number": 7, + "is_secret": false + } + ], + "mock_credentials/ca-phl-reportstream-private-key-local": [ + { + "type": "Private Key", + "filename": "mock_credentials/ca-phl-reportstream-private-key-local", + "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_verified": false, + "line_number": 1, + "is_secret": false + } + ], + "mock_credentials/ca-phl-sftp-host-private-key-local": [ + { + "type": "Private Key", + "filename": "mock_credentials/ca-phl-sftp-host-private-key-local", + "hashed_secret": "27c6929aef41ae2bcadac15ca6abcaff72cda9cd", + "is_verified": false, + "line_number": 1, + "is_secret": false + } + ], + "mock_credentials/ca-phl-sftp-user-credential-private-key-local": [ + { + "type": "Private Key", + "filename": "mock_credentials/ca-phl-sftp-user-credential-private-key-local", + "hashed_secret": "27c6929aef41ae2bcadac15ca6abcaff72cda9cd", + "is_verified": false, + "line_number": 1, + "is_secret": false + } + ], + "src/orchestration/queue_test.go": [ + { + "type": "Azure Storage Account access key", + "filename": "src/orchestration/queue_test.go", + "hashed_secret": "5666459779d6a76bea73453137803fd27d8f79cd", + "is_verified": false, + "line_number": 35, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "src/orchestration/queue_test.go", + "hashed_secret": "8f5ef7ea81fecd1995e8920912b87b232ab41d42", + "is_verified": false, + "line_number": 35, + "is_secret": false + } + ], + "src/senders/report_stream_sender_test.go": [ + { + "type": "Secret Keyword", + "filename": "src/senders/report_stream_sender_test.go", + "hashed_secret": "493a7b3422cad32ee6eeec182085be8a776a27da", + "is_verified": false, + "line_number": 18, + "is_secret": false + }, + { + "type": "JSON Web Token", + "filename": "src/senders/report_stream_sender_test.go", + "hashed_secret": "60cedfd5328355305997af2d7cb822adcd358490", + "is_verified": false, + "line_number": 96, + "is_secret": false + } + ] + }, + "generated_at": "2024-09-16T15:04:44Z" } diff --git a/README.md b/README.md index 39aedc77..5135f3c9 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ match your newly-created file ```json { "topic": "/subscriptions/52203171-a2ed-4f6c-b5cf-9b368c43f15b/resourceGroups/csels-rsti-internal-moderate-rg/providers/Microsoft.Storage/storageAccounts/cdcrssftpinternal", - "subject": "/blobServices/default/containers/sftp/blobs/order_message.hl7", + "subject": "/blobServices/default/containers/sftp/blobs/import/order_message.hl7", "eventType": "Microsoft.Storage.BlobCreated", "id": "dac45448-001e-0031-7649-b8ad2c06c977", "data": { @@ -92,7 +92,7 @@ match your newly-created file "contentType": "application/octet-stream", "contentLength": 1122, "blobType": "BlockBlob", - "url": "https://cdcrssftpinternal.blob.core.windows.net/sftp/order_message.hl7", + "url": "http://127.0.0.1:12000/devstoreaccount1/sftp/import/order_message.hl7", "sequencer": "00000000000000000000000000024DA1000000000006ab03", "storageDiagnostics": { "batchId": "6677b768-3006-0093-0049-b89735000000" @@ -114,12 +114,31 @@ As of 7/3/24, when we copy a file from the local SFTP server, we try to unzip it files into the import folder, and if there are any errors, we upload an error file for the zip. If the original file is not a zip, we just copy it into the import folder. -#### Manual cloud testing -To trigger file ingestion in a deployed environment, go to the `cdcrssftp{env}` storage account in the Azure portal. +#### Manual Cloud Testing + +##### Upload to Our Azure Container + +To trigger file ingestion in a deployed environment, go to the `cdcrssftp{env}` storage account in the Azure Portal. In the `sftp` container, upload a file to an `import` folder. If that folder doesn't already exist, you can create it by going to `Upload`, expanding `Advanced`, and putting `import` in the `Upload to folder` box! [upload_file.png](docs/upload_file.png) +##### Upload to SFTP Server + +Log into CA's SFTP staging environment and drop a file into the `OUTPUT` folder. You can either wait for one of our +lower environments to trigger, or you can manually trigger the Azure function from the Azure Portal. + +The credentials and domain name for CA's SFTP environment can be found in Keybase under CA Info. + +To manually trigger the Azure function... + +1. If this is in an Azure Entra domain environment, you will need to log in as your -SU account. +2. Go to the `polling-function-{env}` function app in the Azure Portal. +3. Navigate to the CORS section, and add `https://portal.azure.com` as an allowed origin. Click save. +4. Navigate back to the Overview section, and click on the trigger function. +5. Click on the Test/Run button, and then click on the Run button that pops-up. + + #### End-to-end Tests #### Load Testing @@ -173,6 +192,10 @@ PR reviews before merge. The Production environment is the real deal. It deploys to a CDC Azure Entra domain and subscription. Deployments occur when a release is published. +### Secrets + +See [SECRETS.md](./SECRETS.md) for a description of our secrets. + ## Related documents * [Azure Functions and Typescript](/azure_functions/src/README.md) diff --git a/SECRETS.md b/SECRETS.md new file mode 100644 index 00000000..b81839a5 --- /dev/null +++ b/SECRETS.md @@ -0,0 +1,58 @@ +# Secrets + +Rotating secrets is tricky and tedious, the purpose of this document is to align contributors with the current state of +secrets and ensure they continue to align as secrets are created/renamed or deleted. + +## Current Secrets + +Below are the secrets that currently exist in Azure KeyVault and what they represent. The `env` part represents the +environment, such as `dev`, `stg`, etc. + +- ZIP password: `ca-phl-zip-password-env`. +- SFTP starting directory: `ca-phl-sftp-starting-directory-env`. +- SFTP server address: `ca-phl-sftp-server-address-env`. +- SFTP username: `ca-phl-sftp-user-env`. +- SFTP server host public key: `ca-phl-sftp-host-public-key-env`. +- SFTP user credential private key: `ca-phl-sftp-user-credential-private-key-env`. +- RS JWT signing key: `ca-phl-reportstream-private-key-env`. + +## Naming Convention + +The current naming convention for secrets is: [partner-name]-[associated-service]-[purpose] + +If we ever have private keys or public keys, include whether it is a private or public key in the [purpose]. See our +existing secrets for inspiration. + +## Types + +Currently, there are two types of secrets to access our partners. Each secret associated with said service will contain +one its name after the partner's name: + +- To access ReportStream: `reportstream` is included in the name. +- To access an external SFTP site: `sftp` is included in the name. + +There are also two types of secrets when it comes to connecting to an SFTP server. + +### The User Credentials + +This is represented as `user-credential-private-key` in our secrets. + +This is a private key that the user (us) has and uses to authenticate to the SFTP server. The associated +public key is given to the SFTP server administrator before we try to connect. + +### The Server's Host Key + +This is represented as `sftp-host-public-key` in our secrets. + +This is a public key that the user (us) has and uses to ensure we are connecting to the correct SFTP server. The +associated private key is pre-created by the SFTP server administrator and installed on the SFTP server. We don't +create the public key, but we can get the public key when we connect to the server or the SFTP server administrator can +give it to us. + +## Local Secrets + +We put mock secrets into [mock_credentials](./mock_credentials) that are used when running the service locally. There +are additional secrets in there than are used by our application. For example, we have a private key for our user +credentials as one of our secrets, but we need an associated public key to be installed on the mock SFTP server for this +to work. So, we have a public key that isn't used by our service but is used by our mock SFTP server to make the +authentication work. A similar concept applies to the SFTP host key and could apply to other secrets. diff --git a/docker-compose.yml b/docker-compose.yml index 226ba028..54e22b27 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,7 @@ services: ENV: local # Uncomment the line below to call local report stream. Otherwise we'll use a mock response # REPORT_STREAM_URL_PREFIX: http://host.docker.internal:7071 - FLEXION_PRIVATE_KEY_NAME: trusted-intermediary-private-key-local.pem #pragma: allowlist secret - FLEXION_CLIENT_NAME: flexion.simulated-hospital + CA_PHL_CLIENT_NAME: flexion.simulated-lab QUEUE_MAX_DELIVERY_ATTEMPTS: 5 POLLING_TRIGGER_QUEUE_NAME: polling-trigger-queue volumes: @@ -51,7 +50,7 @@ services: - -c - | az storage container create -n sftp - az storage blob upload --overwrite --account-name devstoreaccount1 --container-name sftp --name order_message.hl7 --file mock_data/order_message.hl7 + az storage blob upload --overwrite --account-name devstoreaccount1 --container-name sftp --name import/order_message.hl7 --file mock_data/order_message.hl7 az storage queue create -n message-import-queue az storage queue create -n message-import-dead-letter-queue az storage queue create -n polling-trigger-queue @@ -96,9 +95,9 @@ services: environment: SFTP_USERS: ti_user:ti_password:::files volumes: -# - ./mock_credentials/sftp-public-key-local:/home/ti_user/.ssh/keys/id_rsa.pub:ro # uncomment me when CA uses our public key for authentication - - ./mock_credentials/sftp-server-private-key-local:/etc/ssh/ssh_host_rsa_key -# - ./localdata/sftp_server_require_password_and_publickey.sh:/etc/sftp.d/sftp_server_require_password_and_publickey.sh # uncomment me when CA uses our public key for authentication + - ./mock_credentials/ca-phl-sftp-user-credential-public-key-local:/home/ti_user/.ssh/keys/id_rsa.pub:ro + - ./mock_credentials/ca-phl-sftp-host-private-key-local:/etc/ssh/ssh_host_rsa_key + - ./localdata/sftp_server_require_publickey.sh:/etc/sftp.d/sftp_server_require_publickey.sh - ./localdata/data/sftp:/home/ti_user/files ports: - "2223:22" diff --git a/localdata/sftp_server_require_password_and_publickey.sh b/localdata/sftp_server_require_password_and_publickey.sh deleted file mode 100755 index 0be3a479..00000000 --- a/localdata/sftp_server_require_password_and_publickey.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -echo "AuthenticationMethods password,publickey" >> /etc/ssh/sshd_config diff --git a/localdata/sftp_server_require_publickey.sh b/localdata/sftp_server_require_publickey.sh new file mode 100755 index 00000000..ee9b7198 --- /dev/null +++ b/localdata/sftp_server_require_publickey.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "AuthenticationMethods publickey" >> /etc/ssh/sshd_config diff --git a/mock_credentials/trusted-intermediary-private-key-local.pem b/mock_credentials/ca-phl-reportstream-private-key-local old mode 100644 new mode 100755 similarity index 100% rename from mock_credentials/trusted-intermediary-private-key-local.pem rename to mock_credentials/ca-phl-reportstream-private-key-local diff --git a/mock_credentials/sftp-server-private-key-local b/mock_credentials/ca-phl-sftp-host-private-key-local similarity index 100% rename from mock_credentials/sftp-server-private-key-local rename to mock_credentials/ca-phl-sftp-host-private-key-local diff --git a/mock_credentials/sftp-server-public-key-local b/mock_credentials/ca-phl-sftp-host-public-key-local similarity index 100% rename from mock_credentials/sftp-server-public-key-local rename to mock_credentials/ca-phl-sftp-host-public-key-local diff --git a/mock_credentials/sftp-password-local b/mock_credentials/ca-phl-sftp-password-local similarity index 100% rename from mock_credentials/sftp-password-local rename to mock_credentials/ca-phl-sftp-password-local diff --git a/mock_credentials/sftp-server-address-local b/mock_credentials/ca-phl-sftp-server-address-local similarity index 100% rename from mock_credentials/sftp-server-address-local rename to mock_credentials/ca-phl-sftp-server-address-local diff --git a/mock_credentials/sftp-starting-directory-local b/mock_credentials/ca-phl-sftp-starting-directory-local similarity index 100% rename from mock_credentials/sftp-starting-directory-local rename to mock_credentials/ca-phl-sftp-starting-directory-local diff --git a/mock_credentials/sftp-key-local b/mock_credentials/ca-phl-sftp-user-credential-private-key-local old mode 100644 new mode 100755 similarity index 100% rename from mock_credentials/sftp-key-local rename to mock_credentials/ca-phl-sftp-user-credential-private-key-local diff --git a/mock_credentials/sftp-public-key-local b/mock_credentials/ca-phl-sftp-user-credential-public-key-local similarity index 100% rename from mock_credentials/sftp-public-key-local rename to mock_credentials/ca-phl-sftp-user-credential-public-key-local diff --git a/mock_credentials/sftp-user-local b/mock_credentials/ca-phl-sftp-user-local similarity index 100% rename from mock_credentials/sftp-user-local rename to mock_credentials/ca-phl-sftp-user-local diff --git a/mock_credentials/ca-dph-zip-password-local b/mock_credentials/ca-phl-zip-password-local similarity index 100% rename from mock_credentials/ca-dph-zip-password-local rename to mock_credentials/ca-phl-zip-password-local diff --git a/operations/template/app.tf b/operations/template/app.tf index f074efea..3472b133 100644 --- a/operations/template/app.tf +++ b/operations/template/app.tf @@ -127,15 +127,14 @@ resource "azurerm_linux_web_app" "sftp" { ENV = var.environment AZURE_STORAGE_CONNECTION_STRING = azurerm_storage_account.storage.primary_blob_connection_string REPORT_STREAM_URL_PREFIX = "https://${local.rs_domain_prefix}prime.cdc.gov" - FLEXION_PRIVATE_KEY_NAME = azurerm_key_vault_secret.mock_public_health_lab_private_key.name AZURE_KEY_VAULT_URI = azurerm_key_vault.key_storage.vault_uri - FLEXION_CLIENT_NAME = "flexion.simulated-lab" + CA_PHL_CLIENT_NAME = "flexion.simulated-lab" QUEUE_MAX_DELIVERY_ATTEMPTS = azurerm_eventgrid_system_topic_event_subscription.topic_sub.retry_policy.0.max_delivery_attempts # making the Azure container <-> queue retry count be in sync with the queue <-> application retry count.. } sticky_settings { - app_setting_names = ["AZURE_STORAGE_CONNECTION_STRING", "REPORT_STREAM_URL_PREFIX", "FLEXION_PRIVATE_KEY_NAME", - "AZURE_KEY_VAULT_URI", "FLEXION_CLIENT_NAME", "QUEUE_MAX_DELIVERY_ATTEMPTS"] + app_setting_names = ["AZURE_STORAGE_CONNECTION_STRING", "REPORT_STREAM_URL_PREFIX", + "AZURE_KEY_VAULT_URI", "CA_PHL_CLIENT_NAME", "QUEUE_MAX_DELIVERY_ATTEMPTS"] } identity { diff --git a/operations/template/key.tf b/operations/template/key.tf index 2c466b20..633bff5d 100644 --- a/operations/template/key.tf +++ b/operations/template/key.tf @@ -27,6 +27,7 @@ resource "azurerm_key_vault_access_policy" "allow_github_deployer" { "Get", "Delete", "Purge", + "Recover", ] key_permissions = [ @@ -77,20 +78,8 @@ resource "azurerm_key_vault_access_policy" "allow_container_registry_wrapping" { } -resource "azurerm_key_vault_secret" "mock_public_health_lab_private_key" { - name = "mock-public-health-lab-private-key-${var.environment}" - value = "dogcow" - - key_vault_id = azurerm_key_vault.key_storage.id - - lifecycle { - ignore_changes = [value] - } - depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret -} - -resource "azurerm_key_vault_secret" "ca_dph_zip_password" { - name = "ca-dph-zip-password-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_reportstream_private_key" { + name = "ca-phl-reportstream-private-key-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -101,8 +90,8 @@ resource "azurerm_key_vault_secret" "ca_dph_zip_password" { depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret } -resource "azurerm_key_vault_secret" "sftp_starting_directory" { - name = "sftp-starting-directory-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_zip_password" { + name = "ca-phl-zip-password-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -113,8 +102,8 @@ resource "azurerm_key_vault_secret" "sftp_starting_directory" { depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret } -resource "azurerm_key_vault_secret" "sftp_user" { - name = "sftp-user-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_sftp_starting_directory" { + name = "ca-phl-sftp-starting-directory-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -125,8 +114,8 @@ resource "azurerm_key_vault_secret" "sftp_user" { depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret } -resource "azurerm_key_vault_secret" "sftp_password" { - name = "sftp-password-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_sftp_user" { + name = "ca-phl-sftp-user-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -137,8 +126,8 @@ resource "azurerm_key_vault_secret" "sftp_password" { depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret } -resource "azurerm_key_vault_secret" "sftp_key" { - name = "sftp-key-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_sftp_user_credential_private_key" { + name = "ca-phl-sftp-user-credential-private-key-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -149,8 +138,8 @@ resource "azurerm_key_vault_secret" "sftp_key" { depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret } -resource "azurerm_key_vault_secret" "sftp_server_address" { - name = "sftp-server-address-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_sftp_server_address" { + name = "ca-phl-sftp-server-address-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -161,8 +150,8 @@ resource "azurerm_key_vault_secret" "sftp_server_address" { depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret } -resource "azurerm_key_vault_secret" "sftp_server_public_key" { - name = "sftp-server-public-key-${var.environment}" +resource "azurerm_key_vault_secret" "ca_phl_sftp_host_public_key" { + name = "ca-phl-sftp-host-public-key-${var.environment}" value = "dogcow" key_vault_id = azurerm_key_vault.key_storage.id @@ -190,4 +179,4 @@ resource "azurerm_key_vault_key" "customer_managed_key" { ] depends_on = [azurerm_key_vault_access_policy.allow_github_deployer] //wait for the permission that allows our deployer to write the secret -} \ No newline at end of file +} diff --git a/src/senders/report_stream_sender.go b/src/senders/report_stream_sender.go index e8a08721..6b041109 100644 --- a/src/senders/report_stream_sender.go +++ b/src/senders/report_stream_sender.go @@ -30,11 +30,13 @@ func NewSender() (Sender, error) { slog.Error("Unable to initialize credential getter", slog.Any(utils.ErrorKey, err)) return Sender{}, err } + // ca-phl-reportstream-private-key + reportStreamPrivateKeyName := utils.CA_PHL + "-reportstream-private-key-" + utils.EnvironmentName() // pragma: allowlist secret return Sender{ baseUrl: os.Getenv("REPORT_STREAM_URL_PREFIX"), - privateKeyName: os.Getenv("FLEXION_PRIVATE_KEY_NAME"), - clientName: os.Getenv("FLEXION_CLIENT_NAME"), + privateKeyName: reportStreamPrivateKeyName, + clientName: os.Getenv("CA_PHL_CLIENT_NAME"), credentialGetter: credentialGetter, }, nil } diff --git a/src/senders/report_stream_sender_test.go b/src/senders/report_stream_sender_test.go index c84618b6..80886d0f 100644 --- a/src/senders/report_stream_sender_test.go +++ b/src/senders/report_stream_sender_test.go @@ -15,6 +15,8 @@ import ( "testing" ) +const reportStreamPrivateKeyName = "ca-phl-reportstream-private-key-local" + type SenderTestSuite struct { suite.Suite } @@ -22,15 +24,13 @@ type SenderTestSuite struct { func (suite *SenderTestSuite) SetupTest() { os.Setenv("ENV", "local") os.Setenv("REPORT_STREAM_URL_PREFIX", "rs.com") - os.Setenv("FLEXION_PRIVATE_KEY_NAME", "key") - os.Setenv("FLEXION_CLIENT_NAME", "client") + os.Setenv("CA_PHL_CLIENT_NAME", "client") } func (suite *SenderTestSuite) TearDownTest() { os.Unsetenv("ENV") os.Unsetenv("REPORT_STREAM_URL_PREFIX") - os.Unsetenv("FLEXION_PRIVATE_KEY_NAME") - os.Unsetenv("FLEXION_CLIENT_NAME") + os.Unsetenv("CA_PHL_CLIENT_NAME") } func (suite *SenderTestSuite) Test_NewSender_VariablesAreSet_ReturnsSender() { @@ -39,8 +39,7 @@ func (suite *SenderTestSuite) Test_NewSender_VariablesAreSet_ReturnsSender() { assert.NoError(suite.T(), err) assert.Equal(suite.T(), os.Getenv("REPORT_STREAM_URL_PREFIX"), sender.baseUrl) - assert.Equal(suite.T(), os.Getenv("FLEXION_PRIVATE_KEY_NAME"), sender.privateKeyName) - assert.Equal(suite.T(), os.Getenv("FLEXION_CLIENT_NAME"), sender.clientName) + assert.Equal(suite.T(), os.Getenv("CA_PHL_CLIENT_NAME"), sender.clientName) } func (suite *SenderTestSuite) Test_NewSender_EnvIsEmpty_ReturnsSenderWithLocalCredentials() { @@ -49,19 +48,17 @@ func (suite *SenderTestSuite) Test_NewSender_EnvIsEmpty_ReturnsSenderWithLocalCr assert.NoError(suite.T(), err) assert.Equal(suite.T(), os.Getenv("REPORT_STREAM_URL_PREFIX"), sender.baseUrl) - assert.Equal(suite.T(), os.Getenv("FLEXION_PRIVATE_KEY_NAME"), sender.privateKeyName) - assert.Equal(suite.T(), os.Getenv("FLEXION_CLIENT_NAME"), sender.clientName) + assert.Equal(suite.T(), os.Getenv("CA_PHL_CLIENT_NAME"), sender.clientName) } func (suite *SenderTestSuite) Test_GenerateJWT_ReturnsJWT() { - sender, err := NewSender() mockCredentialGetter := new(mocks.MockCredentialGetter) sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) jwt, err := sender.generateJwt() assert.NoError(suite.T(), err) @@ -75,7 +72,7 @@ func (suite *SenderTestSuite) Test_GenerateJWT_UnableToGetPrivateKey_ReturnsErro mockCredentialGetter := new(mocks.MockCredentialGetter) sender.credentialGetter = mockCredentialGetter - mockCredentialGetter.On("GetPrivateKey", "key").Return(&rsa.PrivateKey{}, errors.New("failed to retrieve private key")) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(&rsa.PrivateKey{}, errors.New("failed to retrieve private key")) _, err = sender.generateJwt() assert.Error(suite.T(), err) @@ -88,7 +85,7 @@ func (suite *SenderTestSuite) Test_getToken_ReturnsAccessToken() { sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -119,7 +116,7 @@ func (suite *SenderTestSuite) Test_getToken_UnableToGenerateJWT_ReturnsError() { mockCredentialGetter := new(mocks.MockCredentialGetter) sender.credentialGetter = mockCredentialGetter - mockCredentialGetter.On("GetPrivateKey", "key").Return(&rsa.PrivateKey{}, errors.New("failed to retrieve private key")) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(&rsa.PrivateKey{}, errors.New("failed to retrieve private key")) token, err := sender.getToken() assert.Error(suite.T(), err) @@ -134,7 +131,7 @@ func (suite *SenderTestSuite) Test_getToken_UnableToCallTokenEndpoint_ReturnsErr sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) token, err := sender.getToken() @@ -149,7 +146,7 @@ func (suite *SenderTestSuite) Test_getToken_ReportStreamResponseStatusIsInvalid_ sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -181,7 +178,7 @@ func (suite *SenderTestSuite) Test_getToken_UnableToMarshallResponseBody_Returns sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -209,7 +206,7 @@ func (suite *SenderTestSuite) Test_SendMessage_MessageSentToReportStream_Returns sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -273,7 +270,7 @@ func (suite *SenderTestSuite) Test_SendMessage_UnableToGetToken_ReturnsError() { sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, errors.New(utils.ErrorKey)) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, errors.New(utils.ErrorKey)) message, _ := os.ReadFile(filepath.Join("..", "..", "mock_data", "order_message.hl7")) @@ -291,7 +288,7 @@ func (suite *SenderTestSuite) Test_SendMessage_UnableToCallTokenEndpoint_Returns sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -330,7 +327,7 @@ func (suite *SenderTestSuite) Test_SendMessage_StatusCodeIsAbove300_ReturnsError sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -396,7 +393,7 @@ func (suite *SenderTestSuite) Test_SendMessage_StatusCodeIs400_ReturnsNonTransie sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -465,7 +462,7 @@ func (suite *SenderTestSuite) Test_SendMessage_StatusCodeIsAbove499_ReturnsError testKey, err := rsa.GenerateKey(rand.Reader, 2048) assert.NoError(suite.T(), err) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) @@ -531,7 +528,7 @@ func (suite *SenderTestSuite) Test_SendMessage_UnableToParseResponseBody_Returns sender.credentialGetter = mockCredentialGetter testKey, err := rsa.GenerateKey(rand.Reader, 2048) - mockCredentialGetter.On("GetPrivateKey", "key").Return(testKey, nil) + mockCredentialGetter.On("GetPrivateKey", reportStreamPrivateKeyName).Return(testKey, nil) // Set up a test server for ReportStream // Response parts: Body, Status Code, Access Token (part of body), Error (part of body) diff --git a/src/sftp/handler.go b/src/sftp/handler.go index 522343c1..e4981930 100644 --- a/src/sftp/handler.go +++ b/src/sftp/handler.go @@ -26,53 +26,44 @@ type SftpHandler struct { func NewSftpHandler(credentialGetter secrets.CredentialGetter) (*SftpHandler, error) { // In the future, we'll pass in info about what customer we're using (and thus what URL/key/password to use) - // TODO uncomment code when partner is setup to receive key - //pem, err := getPublicKeysForSshClient(credentialGetter) - //if err != nil { - // return nil, err - //} - - serverKeySecret := "sftp-server-public-key-" + utils.EnvironmentName() // pragma: allowlist secret - serverKey, err := credentialGetter.GetSecret(serverKeySecret) + userCredentialPrivateKey, err := getUserCredentialPrivateKey(credentialGetter) if err != nil { - slog.Error("Unable to get server key secret", slog.String("KeyName", serverKeySecret), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable to get user credential private key", slog.Any(utils.ErrorKey, err)) return nil, err } - hostKeyCallback, err := getSshClientHostKeyCallback(serverKey) + hostPublicKeyName := utils.CA_PHL + "-sftp-host-public-key-" + utils.EnvironmentName() // pragma: allowlist secret + hostPublicKey, err := credentialGetter.GetSecret(hostPublicKeyName) if err != nil { - slog.Error("Unable to get SSH Client Host Key", slog.Any("KeyName", hostKeyCallback), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable to get host public key", slog.String("KeyName", hostPublicKeyName), slog.Any(utils.ErrorKey, err)) return nil, err } - sftpUserNameSecret := "sftp-user-" + utils.EnvironmentName() // pragma: allowlist secret - sftpUser, err := credentialGetter.GetSecret(sftpUserNameSecret) + hostKeyCallback, err := getSshClientHostKeyCallback(hostPublicKey) if err != nil { - slog.Error("Unable to get SFTP username secret", slog.String("KeyName", sftpUserNameSecret), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable construct the host key callback", slog.Any("KeyName", hostPublicKeyName), slog.Any(utils.ErrorKey, err)) return nil, err } - sftpPasswordSecret := "sftp-password-" + utils.EnvironmentName() // pragma: allowlist secret - sftpPassword, err := credentialGetter.GetSecret(sftpPasswordSecret) + sftpUserName := utils.CA_PHL + "-sftp-user-" + utils.EnvironmentName() // pragma: allowlist secret + sftpUser, err := credentialGetter.GetSecret(sftpUserName) if err != nil { - slog.Error("Unable to get SFTP password secret", slog.String("KeyName", sftpPasswordSecret), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable to get SFTP username secret", slog.String("KeyName", sftpUserName), slog.Any(utils.ErrorKey, err)) return nil, err } - // TODO uncomment code when partner is setup to receive key config := &ssh.ClientConfig{ User: sftpUser, Auth: []ssh.AuthMethod{ - //ssh.PublicKeys(pem), - ssh.Password(sftpPassword), + ssh.PublicKeys(userCredentialPrivateKey), }, HostKeyCallback: hostKeyCallback, } - sftpServerAddressSecret := "sftp-server-address-" + utils.EnvironmentName() // pragma: allowlist secret - sftpServerAddress, err := credentialGetter.GetSecret(sftpServerAddressSecret) + sftpServerAddressName := utils.CA_PHL + "-sftp-server-address-" + utils.EnvironmentName() // pragma: allowlist secret + sftpServerAddress, err := credentialGetter.GetSecret(sftpServerAddressName) if err != nil { - slog.Error("Unable to get SFTP server address secret", slog.String("KeyName", sftpServerAddressSecret), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable to get SFTP server address secret", slog.String("KeyName", sftpServerAddressName), slog.Any(utils.ErrorKey, err)) return nil, err } @@ -121,13 +112,13 @@ func getSshClientHostKeyCallback(serverKey string) (ssh.HostKeyCallback, error) return ssh.FixedHostKey(pk), nil } -func getPublicKeysForSshClient(credentialGetter secrets.CredentialGetter) (ssh.Signer, error) { +func getUserCredentialPrivateKey(credentialGetter secrets.CredentialGetter) (ssh.Signer, error) { - userAuthenticationKeySecret := "sftp-key-" + utils.EnvironmentName() // pragma: allowlist secret + userAuthenticationKeyName := utils.CA_PHL + "-sftp-user-credential-private-key-" + utils.EnvironmentName() // pragma: allowlist secret - key, err := credentialGetter.GetSecret(userAuthenticationKeySecret) + key, err := credentialGetter.GetSecret(userAuthenticationKeyName) if err != nil { - slog.Error("Unable to retrieve user authentication key secret", slog.String("KeyName", userAuthenticationKeySecret), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable to retrieve user authentication key secret", slog.String("KeyName", userAuthenticationKeyName), slog.Any(utils.ErrorKey, err)) return nil, err } @@ -157,10 +148,10 @@ func (receiver *SftpHandler) Close() { } func (receiver *SftpHandler) CopyFiles() { - sftpStartingDirectorySecret := "sftp-starting-directory-" + utils.EnvironmentName() // pragma: allowlist secret - sftpStartingDirectory, err := receiver.credentialGetter.GetSecret(sftpStartingDirectorySecret) + sftpStartingDirectoryName := utils.CA_PHL + "-sftp-starting-directory-" + utils.EnvironmentName() // pragma: allowlist secret + sftpStartingDirectory, err := receiver.credentialGetter.GetSecret(sftpStartingDirectoryName) if err != nil { - slog.Error("Unable to get SFTP starting directory secret", slog.String("KeyName", sftpStartingDirectorySecret), slog.Any(utils.ErrorKey, err)) + slog.Error("Unable to get SFTP starting directory secret", slog.String("KeyName", sftpStartingDirectoryName), slog.Any(utils.ErrorKey, err)) return } diff --git a/src/sftp/handler_test.go b/src/sftp/handler_test.go index efda8f90..a668a3d8 100644 --- a/src/sftp/handler_test.go +++ b/src/sftp/handler_test.go @@ -18,8 +18,12 @@ import ( ) const serverKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDg90HXaJnI1KtfJp8MWHxAwC00PvQCZKm4FRRdPGhEMepXIeLdjOtZV6LdePMT3WUmNkd6vaJ4EEmFUtH9lKLidALL9blOJF1iZKXK81JBJsds8axz5cqAau6aclgc9B1z2tAa+JtaSqN7uXvfPsrmsVss4jcOxX+thAhz7U6chN6ahabgIPqHBEjwvPlVNNbSqv0Q0eS4WaEEo/39tiXn5DYpPRC6DjuZ3m5s3VIgHznTv2Ufp3kcLcfEDZFwjm5XRWLNNvM5h3aW1vmr4lgBwuEzPV7CYIdIyDxe9V7YYcGfO+uu/VrDpY1wSmcD3lzHLLTbi5WWOurwiMsWIVRZfa/rmzuoTYknd5iJoiTyIWmR7L0FLfzPlDYJZmAWSdLZrZaUdD8SDIoKMSEV/5/ZzcI0wuoknis+zpyFqT0jfOy7E4GtG8pEQf7JGXaiExNd9TKxbRmaxp3Yv4WgPBThY39Va7EMUC/s0hX2Ah8pIWZG4Lze4x7Z4dElCOHDgnsl3Akc399jnIDfUY4bVn+rfBJntx9mBRaNnV1GqRodbSkHK5dTcZEmRslhuhsQVO2CxrlkPhFEe0XXpA3llO9YIkf4sCZDUbRFKPJiHyDhfrf2/HzkLndODdFaAnICYd51zOI1SgP3aFx60bZ2nPSoLs9DsR1LLIpz4uoiy5hCHw== sschuresko@flexion-mac-J40DPF4YQR" +const user = "ti_user" +const secretValue = "-----BEGIN OPENSSH PRIVATE KEY-----\n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\n-----END OPENSSH PRIVATE KEY-----\n" // pragma: allowlist secret +const invalidSecretValue = "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn\nNhAAAAAwEAAQAAAgEAumdM026JYzIrA3aNXWY4o6SMcxRyIxmzU8ySo21iuT7NAbuPJXmJ\nyjw6WaMlIktUT1r/bV+/bOV41yNFiYUld7ZB6xIiBEESf7iNZYp3kboNvRI9gQiHtlYV+d\nawQwFb35w+0mlvjR2faSCdFPs6p6GiZdn9k1qG+CewSB9UbqG4kUV385vKke4zDe7EH8g9\nvLPWosYIqEkgHAjPwEArc9izuXTCR2Dsl0xLfwcNc8Xf/Su77Id/55yNIGr8gRBGPjtiwW\nBMN0PSyV109yyDBq6vjeDDZ9SHKSoErYnhFHnTkjprIlgR9/5jSVCBpr8eIdo1iRuLLzLh\nmQ8DZN+y7OsAwlJc1kEa5U4ubwmFxMqoCNRPBhqXdm+LDIx+7slEvHoOJPqMuiF+e3THpM\nk5vAwITlBVZtj3I/qkap2MR6lg+zkdW2cW8Ml+VxCmWT+sykoNR4DkNM7H9wi0wAwT74zG\nlQ72YSwvoaWMc3VSYPMpaVaJV+jhujBGUV3E2Ay9LfdR1oWZPJQs/RI0WuZOZkczv7sNR6\nNvHLl6VIsHcnvYY+prmFmEwJ+bHsysVsp7m/In46GLgZr73MSDznJntxRvPF+NVH58MtbP\n3i9IECBCH0BCG0waYQooKM1grdf3+da8ZA+tbakRcPjO89Gn+65jvBUM8+8VJt8jNA6tcm\nUAAAdIBj7vigY+74oAAAAHc3NoLXJzYQAAAgEAumdM026JYzIrA3aNXWY4o6SMcxRyIxmz\nU8ySo21iuT7NAbuPJXmJyjw6WaMlIktUT1r/bV+/bOV41yNFiYUld7ZB6xIiBEESf7iNZY\np3kboNvRI9gQiHtlYV+dawQwFb35w+0mlvjR2faSCdFPs6p6GiZdn9k1qG+CewSB9UbqG4\nkUV385vKke4zDe7EH8g9vLPWosYIqEkgHAjPwEArc9izuXTCR2Dsl0xLfwcNc8Xf/Su77I\nd/55yNIGr8gRBGPjtiwWBMN0PSyV109yyDBq6vjeDDZ9SHKSoErYnhFHnTkjprIlgR9/5j\nSVCBpr8eIdo1iRuLLzLhmQ8DZN+y7OsAwlJc1kEa5U4ubwmFxMqoCNRPBhqXdm+LDIx+7s\nlEvHoOJPqMuiF+e3THpMk5vAwITlBVZtj3I/qkap2MR6lg+zkdW2cW8Ml+VxCmWT+sykoN\nR4DkNM7H9wi0wAwT74zGlQ72YSwvoaWMc3VSYPMpaVaJV+jhujBGUV3E2Ay9LfdR1oWZPJ\nQs/RI0WuZOZkczv7sNR6NvHLl6VIsHcnvYY+prmFmEwJ+bHsysVsp7m/In46GLgZr73MSD\nznJntxRvPF+NVH58MtbP3i9IECBCH0BCG0waYQooKM1grdf3+da8ZA+tbakRcPjO89Gn+6\n5jvBUM8+8VJt8jNA6tcmUAAAADAQABAAACAQCAqZTJy95g7dvqxAXHlis6KPYY6N/vgmnZ\nSbddvr8KBmMS8xdXUpDdWr0b6hRTm5NSQwlTwWcsDyhdtybkSVcXTmIpk5aPQSs3pXdTw0\nPM/pNFEjYJvo2OOdVpYdrAJUv5CKwEKGqrCOtjcPN76/0Mf/DMRK9W6oGHAD4ZSibJRi9T\ndpPZPouQNs5eq5QMK/cRLUDVkcOgBPl44Ewl8yULDWTgecsv4aLsu+jQgVmzs71rzqgkF1\nMd111CJxarL0SM6Ai+WW3CJ7py62M0yTCXiDP8xkuae4Pf0fTwo98MdxqmMFSKnCeq+Zgm\nnr8fDYQK8cdKIAzuQzycnVRGaHHjEIQSAVv3qfxzb2lk8qCB2NTGvjfMFITJoKYyPWb7Jj\nb41EPk8NZGqOVch5a44vvrHYsuNwdk40+YtNodQ0DREDTtvplAUcmSwZrIACj7I/PsYRZx\nWCiSlJ6UxpdBbFJ7HpTDwlPQMkUzmxVQzg+abtqI7mZPomS/EZ2xtNpwm98p0pyell9wGw\nsiZBi6Mt6iPsKDdQTK6XbTZnYnLuIzXcpSJ/gTAavvyn3D5Up2LUU/NmTpUsuqoTz/VSjb\ntlVaDiz2nmem3zvC1t01PV+aSo39Wg4AMG2moEo/buZhfAqXUMz1XmYJ3js0fY0HUoq4RS\nqfd90aWhqmQmcTbpkScQAAAQEAuMHiHwAGi34hprW61Qxmu1b3XlicLW0kSP5qjn4l6kM9\nT44J1KSbU90Bs/FZq9GPfYazHEPf4j1BleHEOcsOTLf86rfkJHtuebU1Lelv3nGGytlfc/\ny6NVXTQXdG/RDIHec3LXX6D/zqfYQPbG4T8flWJ5c7/JtVScflhRp1SmjesoHkgq83eZI9\nY0j9W8CLA/LrMQnEq8SzL1p+Cj2n2aIwZhX9hS/VkQFDmvZ0w9Z4rxNRnsMxwabni1A84g\nP7qDZltTpJZLZ9BRlhP9hkqmO8tlDH2Lj1j8DaxlUlPNVzJTUY+SjctE/eLvYSWduUHJ9w\npgZvfwzVfoRd67T0ZwAAAQEA4hzssuT34awOuP6SCg6tshu9ORfDmSiZHdolnNcOpe9GZm\ncg/aR4RcPjrpeQxEIEjlEBbvyXu+G5A3rr+SCnBduD0szzpAkVkAAy3+Tat9iNhrPxD5bU\nTc1VSaSiAln533cdgqBRAXp7zU5vXhD3DA1cWmhjoLnkggfp96kX9z13zw66n7IiQF9BDW\ns1AuUGhjFxtxXvkdncS4EjijwSSCSMu3ttEwpXrQXJjmbER5GkxEIX1jJTLgCukzEsAFG8\nwDVTBxB3QNi+luucoKRyzZlf2fc+m529M+QnVCxWu4ElQsssexDEX/mGdYU9IIDhP9KaRA\nRQ/OZX9/8tAPCHqwAAAQEA0wq11SyeNXx67U63Go2iQnTkKWIqjdVIuQd4vgdmXiHglmBE\nxTmd7VFNBZ7Waje4y7WmMVYdoCAlyOYpKGdwGX5HjE3r4D60HN7+zOYxSdUBUCJWykER1Y\nVjQxSwnSkh4Xdil3QK7Ql1nYRfNSgOwMHd5RyBglSC88eh2vtH5FU8OafzBYmfDkSAdyy2\n5vX83kv5oMUoliJuyFSz7b/AF3b+OAxVxwQfy1J+2ufErRbxNIePfc/EhoSD0MxZD8SebR\nZG0RV/SBTxh5UMmFKqx5OsXJuG7WRmuqqY8+LHDy0JtcKYeEYkSuX2u4JeY1xrcyVU9jM/\nx02R0p/Ln1ueLwAAAA1tZUBoYWxwcmluLmlvAQIDBA==\n-----END OPENSSH PRIVATE KEY-----\n" //pragma: allowlist secret +const invalidServerKey = "AAAAB3NzaC1yc2EAAAADAQABAAACAQDg90HXaJnI1KtfJp8MWHxAwC00PvQCZKm4FRRdPGhEMepXIeLdjOtZV6LdePMT3WUmNkd6vaJ4EEmFUtH9lKLidALL9blOJF1iZKXK81JBJsds8axz5cqAau6aclgc9B1z2tAa+JtaSqN7uXvfPsrmsVss4jcOxX+thAhz7U6chN6ahabgIPqHBEjwvPlVNNbSqv0Q0eS4WaEEo/39tiXn5DYpPRC6DjuZ3m5s3VIgHznTv2Ufp3kcLcfEDZFwjm5XRWLNNvM5h3aW1vmr4lgBwuEzPV7CYIdIyDxe9V7YYcGfO+uu/VrDpY1wSmcD3lzHLLTbi5WWOurwiMsWIVRZfa/rmzuoTYknd5iJoiTyIWmR7L0FLfzPlDYJZmAWSdLZrZaUdD8SDIoKMSEV/5/ZzcI0wuoknis+zpyFqT0jfOy7E4GtG8pEQf7JGXaiExNd9TKxbRmaxp3Yv4WgPBThY39Va7EMUC/s0hX2Ah8pIWZG4Lze4x7Z4dElCOHDgnsl3Akc399jnIDfUY4bVn+rfBJntx9mBRaNnV1GqRodbSkHK5dTcZEmRslhuhsQVO2CxrlkPhFEe0XXpA3llO9YIkf4sCZDUbRFKPJiHyDhfrf2/HzkLndODdFaAnICYd51zOI1SgP3aFx60bZ2nPSoLs9DsR1LLIpz4uoiy5hCHw== sschuresko@flexion-mac-J40DPF4YQR" -func Test_NewSFTPHandler_UnableToGetSFTPServerPublicKeyNameSecret_ReturnsError(t *testing.T) { +func Test_NewSFTPHandler_UnableToGetUserCredentialPrivateKey_ReturnsError(t *testing.T) { buffer, defaultLogger := utils.SetupLogger() defer slog.SetDefault(defaultLogger) @@ -30,58 +34,55 @@ func Test_NewSFTPHandler_UnableToGetSFTPServerPublicKeyNameSecret_ReturnsError(t assert.Nil(t, sftpHandler) assert.Error(t, err) - assert.Contains(t, buffer.String(), "Unable to get server key secret") + assert.Contains(t, buffer.String(), "Unable to get user credential private key") } -func Test_NewSFTPHandler_UnableToGetSSHClientHostKeyCallback_ReturnsError(t *testing.T) { +func Test_NewSFTPHandler_UnableToGetSFTPServerPublicKeyNameSecret_ReturnsError(t *testing.T) { buffer, defaultLogger := utils.SetupLogger() defer slog.SetDefault(defaultLogger) mockCredentialGetter := new(mocks.MockCredentialGetter) - - mockCredentialGetter.On("GetSecret", mock.Anything).Return("test123", nil) + mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return("", errors.New("error")) sftpHandler, err := NewSftpHandler(mockCredentialGetter) assert.Nil(t, sftpHandler) assert.Error(t, err) - - assert.Contains(t, buffer.String(), "Unable to get SSH Client Host Key") + assert.Contains(t, buffer.String(), "Unable to get host public key") } -func Test_NewSFTPHandler_UnableToGetSFTPUserNameSecret_ReturnsError(t *testing.T) { +func Test_NewSFTPHandler_UnableToGetSSHClientHostKeyCallback_ReturnsError(t *testing.T) { buffer, defaultLogger := utils.SetupLogger() defer slog.SetDefault(defaultLogger) mockCredentialGetter := new(mocks.MockCredentialGetter) - serverKey := serverKey - - mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Once() - mockCredentialGetter.On("GetSecret", mock.Anything).Return("", errors.New("error")) + mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil) sftpHandler, err := NewSftpHandler(mockCredentialGetter) assert.Nil(t, sftpHandler) assert.Error(t, err) - assert.Contains(t, buffer.String(), "Unable to get SFTP username secret") + + assert.Contains(t, buffer.String(), "Unable construct the host key callback") } -func Test_NewSFTPHandler_UnableToGetSFTPPasswordName_ReturnsError(t *testing.T) { +func Test_NewSFTPHandler_UnableToGetSFTPUserNameSecret_ReturnsError(t *testing.T) { buffer, defaultLogger := utils.SetupLogger() defer slog.SetDefault(defaultLogger) - mockCredentialGetter := new(mocks.MockCredentialGetter) - serverKey := serverKey + mockCredentialGetter := new(mocks.MockCredentialGetter) - mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Twice() + mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Once() mockCredentialGetter.On("GetSecret", mock.Anything).Return("", errors.New("error")) sftpHandler, err := NewSftpHandler(mockCredentialGetter) assert.Nil(t, sftpHandler) assert.Error(t, err) - assert.Contains(t, buffer.String(), "Unable to get SFTP password secret") + assert.Contains(t, buffer.String(), "Unable to get SFTP username secret") } func Test_NewSFTPHandler_UnableToGetSFTPServerAddressName_ReturnsError(t *testing.T) { @@ -90,9 +91,9 @@ func Test_NewSFTPHandler_UnableToGetSFTPServerAddressName_ReturnsError(t *testin mockCredentialGetter := new(mocks.MockCredentialGetter) - serverKey := serverKey - - mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Times(3) + mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return(user, nil).Once() mockCredentialGetter.On("GetSecret", mock.Anything).Return("", errors.New("error")) sftpHandler, err := NewSftpHandler(mockCredentialGetter) @@ -108,9 +109,10 @@ func Test_NewSFTPHandler_UnableToDialIntoTCP_ReturnsError(t *testing.T) { mockCredentialGetter := new(mocks.MockCredentialGetter) - serverKey := serverKey - - mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Times(4) + mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return(serverKey, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return(user, nil).Once() + mockCredentialGetter.On("GetSecret", mock.Anything).Return("wrong-value", nil).Once() sftpHandler, err := NewSftpHandler(mockCredentialGetter) @@ -128,21 +130,17 @@ func Test_getSshClientHostKeyCallback_ReturnsFixedHostKeyCallback(t *testing.T) } func Test_getSshClientHostKeyCallback_UnableToParseServerKey_ReturnsError(t *testing.T) { - serverKey := "AAAAB3NzaC1yc2EAAAADAQABAAACAQDg90HXaJnI1KtfJp8MWHxAwC00PvQCZKm4FRRdPGhEMepXIeLdjOtZV6LdePMT3WUmNkd6vaJ4EEmFUtH9lKLidALL9blOJF1iZKXK81JBJsds8axz5cqAau6aclgc9B1z2tAa+JtaSqN7uXvfPsrmsVss4jcOxX+thAhz7U6chN6ahabgIPqHBEjwvPlVNNbSqv0Q0eS4WaEEo/39tiXn5DYpPRC6DjuZ3m5s3VIgHznTv2Ufp3kcLcfEDZFwjm5XRWLNNvM5h3aW1vmr4lgBwuEzPV7CYIdIyDxe9V7YYcGfO+uu/VrDpY1wSmcD3lzHLLTbi5WWOurwiMsWIVRZfa/rmzuoTYknd5iJoiTyIWmR7L0FLfzPlDYJZmAWSdLZrZaUdD8SDIoKMSEV/5/ZzcI0wuoknis+zpyFqT0jfOy7E4GtG8pEQf7JGXaiExNd9TKxbRmaxp3Yv4WgPBThY39Va7EMUC/s0hX2Ah8pIWZG4Lze4x7Z4dElCOHDgnsl3Akc399jnIDfUY4bVn+rfBJntx9mBRaNnV1GqRodbSkHK5dTcZEmRslhuhsQVO2CxrlkPhFEe0XXpA3llO9YIkf4sCZDUbRFKPJiHyDhfrf2/HzkLndODdFaAnICYd51zOI1SgP3aFx60bZ2nPSoLs9DsR1LLIpz4uoiy5hCHw== sschuresko@flexion-mac-J40DPF4YQR" - actualParsedKeyCallback, err := getSshClientHostKeyCallback(serverKey) + actualParsedKeyCallback, err := getSshClientHostKeyCallback(invalidServerKey) assert.Nil(t, actualParsedKeyCallback) assert.Error(t, err) } func Test_getPublicKeysForSshClient_ReturnsPem(t *testing.T) { - - secretValue := "-----BEGIN OPENSSH PRIVATE KEY-----\n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\n-----END OPENSSH PRIVATE KEY-----\n" //pragma: allowlist secret - mockCredentialGetter := new(mocks.MockCredentialGetter) mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil) - pem, err := getPublicKeysForSshClient(mockCredentialGetter) + pem, err := getUserCredentialPrivateKey(mockCredentialGetter) mockCredentialGetter.AssertCalled(t, "GetSecret", mock.Anything) assert.NotNil(t, pem) @@ -150,11 +148,10 @@ func Test_getPublicKeysForSshClient_ReturnsPem(t *testing.T) { } func Test_getPublicKeysForSshClient_UnableToRetrieveSFTPKey_ReturnsError(t *testing.T) { - mockCredentialGetter := new(mocks.MockCredentialGetter) mockCredentialGetter.On("GetSecret", mock.Anything).Return("", errors.New(utils.ErrorKey)) - pem, err := getPublicKeysForSshClient(mockCredentialGetter) + pem, err := getUserCredentialPrivateKey(mockCredentialGetter) mockCredentialGetter.AssertCalled(t, "GetSecret", mock.Anything) assert.Nil(t, pem) @@ -162,13 +159,10 @@ func Test_getPublicKeysForSshClient_UnableToRetrieveSFTPKey_ReturnsError(t *test } func Test_getPublicKeysForSshClient_UnableToParsePrivateKey_ReturnsError(t *testing.T) { - - secretValue := "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\n-----END OPENSSH PRIVATE KEY-----\n" //pragma: allowlist secret - mockCredentialGetter := new(mocks.MockCredentialGetter) - mockCredentialGetter.On("GetSecret", mock.Anything).Return(secretValue, nil) + mockCredentialGetter.On("GetSecret", mock.Anything).Return(invalidSecretValue, nil) - pem, err := getPublicKeysForSshClient(mockCredentialGetter) + pem, err := getUserCredentialPrivateKey(mockCredentialGetter) mockCredentialGetter.AssertCalled(t, "GetSecret", mock.Anything) assert.Nil(t, pem) diff --git a/src/utils/constants.go b/src/utils/constants.go index 666376c7..fcd8f2e3 100644 --- a/src/utils/constants.go +++ b/src/utils/constants.go @@ -28,3 +28,7 @@ const ErrorKey = "error" // Used in logging. // E.g. `slog.Info("Successfully copied file and removed from SFTP server", slog.Any(utils.FileNameKey, fileInfo.Name()))` const FileNameKey = "file name" + +// The name to uniquely identify California's (CA) public health lab (PHL) +// Used to prepend CA-PHL specific secrets +const CA_PHL = "ca-phl" diff --git a/src/zip/zip.go b/src/zip/zip.go index 33636b56..0cecf022 100644 --- a/src/zip/zip.go +++ b/src/zip/zip.go @@ -55,7 +55,7 @@ func NewZipHandler() (ZipHandler, error) { func (zipHandler ZipHandler) Unzip(zipFilePath string) error { slog.Info("Preparing to unzip", slog.String("zipFilePath", zipFilePath)) - zipPasswordSecret := "ca-dph-zip-password-" + utils.EnvironmentName() // pragma: allowlist secret + zipPasswordSecret := utils.CA_PHL + "-zip-password-" + utils.EnvironmentName() // pragma: allowlist secret zipPassword, err := zipHandler.credentialGetter.GetSecret(zipPasswordSecret) if err != nil { slog.Error("Unable to get zip password", slog.Any(utils.ErrorKey, err), slog.String("KeyName", zipPasswordSecret))