TeamCity Cloud 2024.03 Help

HashiCorp Vault Integration

HashiCorp Vault is a secure storage for your tokens, passwords, certificates, and encryption keys. Instead of storing sensitive information inside TeamCity parameters and tokens, you can keep it in Vault and set up TeamCity to securely access this data from Vault engines (KV/KV2, AWS, Google Cloud, and others).

Common Information

To set up an integration with HashiCorp Vault, you need the following:

  • The HashiCorp Vault connection in the required project (or <Root project>, if you want any TeamCity project to use this connection).

  • The parameter that will store a Vault path to a required secret.

  • References to this parameter (%parameter_name%) in your build steps (for example, in a Command Line runner that executes the terraform apply -var password=%myVaultParam% line).

When a build that utilizes this parameter starts, the TeamCity server uses the Vault connection to request a one-time response wrapping token, which it then passes to a TeamCity agent that runs this build. The build agent uses this token to request Vault secrets and never shares obtained credentials with the TeamCity server. When the build finishes, the agent's token is revoked.

Since all communication with Vault is orchestrated by the TeamCity server, this integration is highly scalable and not affected by the number of build agents accessing Vault secrets. The tokens received by agents from the TeamCity server are not lease tokens (which are solely utilized for testing Vault connections), thus the number of actual build agents does not impact your quota. Consequently, only one Vault license for the TeamCity server is required.

Set Up a Vault Connection

Vault connection settings
  1. Navigate to Administration | <Your Project> | Connections and click Add Connection.

  2. Choose HashiCorp Vault as the connection type.

  3. Specify the basic connection settings: the connection name, Vault URL and namespace, and an optional ID.

    • Vault namespaces allow you to create "vaults within a vault" — isolated tenants inside a single Vault Enterprise instance. If you store Vault secrets in this isolated environment, specify its namespace in the Vault namespace connection field (for example, TeamABC/secrets/). Otherwise, leave this setting empty.

    • ID is a custom string that identifies this Vault connection. You can specify this field if you set up multiple Vault connections and specify which connection a specific parameter should use. Otherwise, leave this field blank.

    • Vault URL is the address of your Vault instance. Local Vault installations (the default URL is http://localhost:8200) are also supported.

  4. Choose the desired authentication method. TeamCity can authenticate to HCP Vault using a Vault's AppRole, an AWS IAM role, or a directory access protocol (LDAP).

    This authentication method requires that you enable the AppRole auth method in your Vault instance and create an AppRole. AppRoles are sets of Vault policies that specify which secrets a user (in this case, TeamCity) can access.

    The Vault AppRole auth method requires you to set up the following settings:

    • AppRole auth endpoint path — the path in your Vault instance where the AppRole auth endpoint is mounted. The default path is approle (without the preceding backslash character).

    • AppRole Role ID and AppRole Secret ID — these values can be obtained in CLI using the following commands:

      vault read -field=role_id auth/<AE>/role/<RN>/role-id vault write -f -field=secret_id auth/<AE>/role/<RN>/secret-id


      where <AE> is the auth endpoint path you specified above (for example, approle) and <RN> is the name of your role (for example, my-teamcity-role).

    Refer to these Vault documentation articles to learn how to create and set up AppRoles: Getting Started: Policies, AppRole auth method.

    This method can be used for Vault instances with enabled LDAP auth method. This authentication option requires username and password. The Path setting stores the path to the LDAP authentication endpoint (for example, ldap for the default auth/ldap/users/userA and auth/ldap/groups/groupB endpoints).

    Refer to this article for more information about setting up this authentication method in Vault: LDAP auth method.

  5. Tick Fail in case of error if you want builds to fail with the "Error while fetching data from HashiCorp Vault" message if the agent cannot obtain Vault secrets and write them to TeamCity parameters. Note that builds will fail even if these parameters are never used. If this setting is disabled, builds will continue running with empty strings as secret parameter values.

Kotlin DSL:

project { features { hashiCorpVaultConnection { id = "PROJECT_EXT_34" name = "HashiCorp Vault" url = "http://127.0.0.1:8200/" vaultNamespace = "enterprise/vault/namespace" authMethod = appRole { roleId = "..." secretId = "..." } failOnError = false } } }

Create and Set Up a Parameter

To start using a secret value from HCP Vault in your builds, create a parameter that serves two purposes:

  • Stores a path to the Vault secret whose value needs to be obtained

  • Stores the secret value after Vault provided it

To create such a parameter, do the following:

  1. Go to Administration | <Project or Build Configuration> | Parameters and click Add new parameter.

  2. Choose the Environment variable type and enter the parameter name. For example, env.AWS_ACCESS_KEY_ID.

  3. Click Edit... next to the "Spec" label and set up the following values:

    • Type: Remote

    • Remote Connection Type: HashiCorp Vault Parameter

    • Parameter Namespace: choose existing Vault connection you wish to use to retrieve this parameter's value. This drop-down menu shows Display names for all connections that have IDs.

      Connection ID
      Parameter ID
    • Vault Query: the path to the secret in the path!/key format. For example, the following string points the parameter to the "access_key" key of the "awscreds" secret stored in the KV2 engine: secret/data/awscreds!/access_key.

  4. Click Save to close the dialog.

Kotlin DSL:

project { params { hashiCorpVaultParameter { name = "env.AWS_ACCESS_KEY_ID" query = "secret/data/awscreds!/access_key" vaultId = "DataLore" } } }

Update Legacy Parameters

If you already used the TeamCity Vault plugin before the 2023.11 version, you might have legacy parameters that store paths to Vault secrets directly in their parameter values (in the %vault:PATH!/KEY% format).

Compared to these legacy parameters, new "remote parameters" showcase the following advantages:

  • Vault paths are stored in the Vault Query field, which leaves the Value field free for the default/initial parameter value.

  • Secret paths (queries) use a more straightforward format without the vault: prefix.

In addition, Vault engines that issue dynamic secrets (for example, the AWS engine) generate new credentials each time a client (TeamCity) sends a new request. For that reason, you should avoid mixing legacy and remote parameters that access the same dynamic secrets engine within the same build.

For example, if you have a remote parameter that obtains the Access Key ID from the Vault AWS engine, and a legacy parameter that retrieves the corresponding Secret Access Key, TeamCity will send separate requests for each parameter. The engine will issue two sets of values, so your ID/Secret pair will mismatch.

We recommend that you update your existing legacy parameters to their remote counterparts.

Kotlin DSL

You can update legacy Vault parameters to a newer type in Kotlin DSL. The legacy Vault parameters are declared like the following:

project { params { param("env.AWS_ACCESS_KEY_ID", "%\vault:secret/data/awscreds!/access_key%") } }

To update these parameters, replace them with the following blocks:

project { params { hashiCorpVaultParameter { name = "env.AWS_ACCESS_KEY_ID" query = "secret/data/awscreds!/access_key" } } }

Note that, unlike the original parameter value, the query field of a new parameter has neither the vault: prefix nor the percent characters.

If your legacy parameter had the %\vault:foobar:/path!/key% format, the "foobar" part identifies which Vault connection this parameter should use to retrieve the secret. Move this value to the vaultId field of a remote parameter:

project { params { hashiCorpVaultParameter { name = "parameter name" query = "path!/key" vaultId = "foobar" } } }
Last modified: 14 May 2024