Secrets and log sanitization
Harness sanitizes deployment logs and any script outputs to mask text secret values and JSON web tokens (JWTs).
First, let's review secrets in Harness, and then look at how Harness sanitizes logs and outputs to prevent secrets from being exposed.
Review: Secrets in Harness
You can create secrets in Harness as described in:
For text and file secrets, the secrets are stored in the Secrets Manager. For steps to add a Secret Manager, go to Add a Secret Manager.
Once a secret is added, you can use other Harness entities instead of settings.
You can reference an Encrypted Text secret created in the Org scope using the secret identifier in the expression: <+secrets.getValue("org.your_secret_Id")>
.
You can reference a file secret created in the Org scope using the expression <+secrets.getValue(“org.file-secret-Id”)>
.
At deployment runtime, the Harness Delegate uses the Secrets Manager to decrypt and read the secret only when it is needed.
Harness sends only encrypted data to the Secrets Manager, as follows:
- Your browser sends data over HTTPS to Harness Manager.
- Harness Manager relays encrypted data to the Harness Delegate, also over HTTPS.
- The delegate exchanges a key pair with the secrets manager, over an encrypted connection.
- The Harness Delegate uses the encrypted key and the encrypted secret, and then discards them. The keys never leave the delegate.
Any secrets manager requires a running Harness Delegate to encrypt and decrypt secrets. Any delegate that references a secret requires direct access to the secrets manager. You can manage your secrets in Harness using either a Key Management Service or third-party Secrets Managers.
Sanitization
When a text secret or a JWT is displayed in a deployment log, Harness substitutes the value with asterisks (*) so that the secret value is never displayed.
For example, if you have a Harness text secret with the identifier doc-secret containing foo
.
You can reference it in a Shell Script step like this:
echo "text secret is: " <+secrets.getValue("doc-secret")>
When you deploy the Pipeline, the log is sanitized and the output is:
Executing command ...
text secret is: **************
Command completed with ExitCode (0)
File secrets are not masked in Harness logs. As noted above they can be encoded in different formats, but they are not masked from users.
Quotes and secrets in a script
By default, secret expressions use quotes for the secret identifier: <+secrets.getValue("secret_identifier")>
.
If the secret value itself includes quotes, either single or double, and anywhere in the secret value, you must use the opposite quote when you use the expression in a script (echo, etc).
If you do not use the opposite quote you will expose the secret value.Single quote example:
Here, the secret value is 'mysecret'
and the identifier is secret_identifier
. To echo, use double quotes:
echo "<+secrets.getValue('secret_identifier')>"
echo "<+secrets.getValue("secret_identifier")>"
Double quote example:
Here, the secret value is "mysecret"
and the identifier is secret_identifier
.
echo '<+secrets.getValue('secret_identifier')>'
Avoid using $
in your secret value. If your secret value includes $
, you must use single quotes when you use the expression in a script.
For example, if your secret value is 'my$secret'
, and the identifier is secret_identifier
, to echo, use single quotes:
echo '<+secrets.getValue("secret_identifier")>'
Kubernetes secret objects
When you deploy a Kubernetes Secret object using Harness, Harness substitutes the secret values with asterisks (*).
Here is a Secret example from the manifest in the Harness Service (using Go templating):
{{- if .Values.dockercfg}}
apiVersion: v1
kind: Secret
metadata:
name: {{.Values.name}}-dockercfg
annotations:
harness.io/skip-versioning: true
data:
.dockercfg: {{.Values.dockercfg}}
type: kubernetes.io/dockercfg
---
{{- end}}
Here is the deployed Secret in the log:
apiVersion: v1
kind: Secret
metadata:
name: harness-example
stringData:
key2: '***'
Changing secrets in scripts and RBAC
Harness log sanitizing only detects exact matches of a secret or any line of it if it is multi-line.
If an operation within a script changes the value of the secret and Harness cannot match it to the expression, the newly modified string is displayed in the output exposing the secret value.
If the modification is minor, the secret value can be easily deciphered which is a security concern.
To avoid this issue, use Harness RBAC to control which users can access a secret.
Log sanitizer detects exact matches only
The log sanitizer detects only exact matches of the secret or any line of the secret if the secret is multiline.