Loading…
Loading…
Explains how the worker service decrypts backend profile credentials using the S2R_CREDENTIAL_KEY and pgcrypto for synthetic monitoring.
The CredentialsCipher is a component within the worker service responsible for decrypting credentials associated with backend profiles. Its primary function is to enable the SyntheticMonitorService to probe authenticated backend APIs by providing it with plaintext credentials at runtime.
This component is designed for decryption only; it never creates or modifies encrypted credentials. It operates by reading an encrypted data structure, called an envelope, and using a symmetric key provided via an environment variable to decrypt it via a database function call. The decryption mechanism uses the pgcrypto extension for PostgreSQL.
The CredentialsCipher is a counterpart to a similar component in the admin-api and runtime services, which handles the encryption of these credentials.
The CredentialsCipher's lifecycle and decryption flow involves initialization, a key-availability check, and a database-backed decryption process.
At startup, the CredentialsCipher component is initialized with the platform's database connection (JdbcTemplate) and the credential decryption key. The key is sourced from the s2r.credential.key configuration property, which defaults to the value of the S2R_CREDENTIAL_KEY environment variable.
After initialization, a pre-flight check runs:
S2R-WRK-0419) but allows the worker service to continue starting. This prevents startup failures in environments where the worker image is used for tasks that do not require credential decryption.WARNING
If the S2R_CREDENTIAL_KEY is not provided, the worker service will start successfully, but all subsequent attempts to decrypt credentials will fail with an IllegalStateException. This will cause synthetic monitor probes against authenticated backends to fail.
The core logic resides in the decryptSecret method, which can handle both modern encrypted "envelopes" and legacy plaintext credentials.
flowchart TD
subgraph "CredentialsCipher.decryptSecret()"
A[Input: Stored credential value] --> B{Is value a JSON envelope?};
B -- Yes --> C[Call internal decrypt()];
C --> D{Is S2R_CREDENTIAL_KEY set?};
D -- No --> E[Throw IllegalStateException];
D -- Yes --> F[Extract 'enc' value from JSON];
F --> G[Execute SQL decryption query];
G --> H[Return plaintext credential];
B -- No (Legacy Plaintext) --> I[Return stored value as-is];
end
H --> Z[Output: Decrypted credential];
I --> Z;
E --> Z_Fail[Output: Failure];Format Detection: The isEnvelope() method checks if the stored string is a JSON object matching the credential envelope format. An envelope is a JSON object with three specific keys: v (version), alg (algorithm, which must be pgcrypto-aes256), and enc (the Base64-encoded ciphertext).
Legacy Handling: If the stored value is not an envelope, it is treated as a legacy plaintext credential and returned directly without any processing. This ensures backward compatibility during migration from plaintext to encrypted credentials.
Decryption: If the value is an envelope, the decrypt() method is called.
S2R_CREDENTIAL_KEY is available. If not, it throws an IllegalStateException.enc field.select pgp_sym_decrypt(decode(?, 'base64'), ?)
decode(?, 'base64') function decodes the ciphertext.pgp_sym_decrypt function uses the provided key to decrypt the data.Consider a credential stored in the database.
Scenario 1: Encrypted Credential The stored value is a JSON envelope:
{"v":1,"alg":"pgcrypto-aes256","enc":"<base64_encoded_ciphertext>"}
The decryptSecret method identifies this as an envelope and proceeds with the decryption flow, ultimately returning the plaintext credential string.
Scenario 2: Legacy Credential The stored value is a simple string:
my_legacy_api_key
The decryptSecret method determines this is not an envelope and returns the string my_legacy_api_key directly.
The CredentialsCipher requires a single environment variable for its operation.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
S2R_CREDENTIAL_KEY | String | "" (empty string) | Yes, for decryption | The symmetric key used to decrypt backend profile credentials. While the worker service can start without it, any decryption operation will fail until this variable is set to the correct key. |
NOTE
The component can also be configured via the Spring property s2r.credential.key, but this property defaults to the value of the S2R_CREDENTIAL_KEY environment variable.
The CredentialsCipher class exposes the following public methods for use within the worker service.
| Method | Return Type | Description |
|---|---|---|
decryptSecret(String stored) | String | The main entry point. It inspects the stored string. If it's a credential envelope, it decrypts it. If not, it returns the string as-is. |
decrypt(String envelopeJson) | String | Decrypts a JSON envelope string into a plaintext JSON string. Throws an IllegalStateException if the decryption key is not configured. Returns null if the input is null or blank. |
decryptToMap(String envelopeJson) | Map<String, Object> | A convenience method that calls decrypt and then parses the resulting plaintext JSON into a Map. Returns an empty map if the input is null, decryption fails, or parsing fails. |
isEnvelope(String stored) | static boolean | A static utility method that returns true if the input string is a well-formed credential envelope. This check does not require a key or a database connection. |
IllegalStateException with the message S2R-WRK-0419 S2R_CREDENTIAL_KEY env var is required for backend-profile credential decryption.S2R_CREDENTIAL_KEY environment variable being set, or the variable was set to an empty string. The component logs a warning at startup (S2R-WRK-0419 S2R_CREDENTIAL_KEY env var is unset...) but only fails when a decryption is actually attempted.S2R_CREDENTIAL_KEY environment variable with the correct symmetric decryption key for the worker service environment and restart the service. The key must be the same one used by the admin-api and runtime services to encrypt the credentials.admin-api and runtime services.