{"id":12600,"date":"2017-09-15T11:40:25","date_gmt":"2017-09-15T11:40:25","guid":{"rendered":"https:\/\/blog.jetbrains.com\/teamcity\/?p=6116"},"modified":"2022-02-24T17:18:58","modified_gmt":"2022-02-24T16:18:58","slug":"vault","status":"publish","type":"teamcity","link":"https:\/\/blog.jetbrains.com\/fr\/teamcity\/2017\/09\/vault","title":{"rendered":"TeamCity Plugin for HashiCorp Vault"},"content":{"rendered":"<p>When performing integration tests and deployments, build scripts need credentials to access external servers and services. Traditionally passwords are stored on the TeamCity server as secure parameters. But although secrets are masked in the UI, encrypted at rest, and protected from being exposed in the build log as plain text, this often does not provide a high enough level of security.<\/p>\n<p><a href=\"https:\/\/www.vaultproject.io\/\" target=\"_blank\" rel=\"noopener\">HashiCorp Vault<\/a> offers a unified approach to managing secrets and credentials, allows auditing access, and helps with password rotation.<\/p>\n<h2>Integration with Vault<\/h2>\n<p>Today we are presenting a new plugin to help build scripts interact with Vault and obtain credentials dynamically.<\/p>\n<p>The plugin allows connecting TeamCity to Vault, requesting new credentials when a build starts, passing them to the build script, and revoking them immediately when the build finishes.<\/p>\n<h3>Usage<\/h3>\n<p>We expect you have installed and configured:<\/p>\n<ul>\n<li>a Vault server. Refer to the <a href=\"https:\/\/www.vaultproject.io\/intro\/getting-started\/install.html\" target=\"_blank\" rel=\"noopener\">Getting Started<\/a>\u00a0guide to learn how to launch a testing Vault instance.<\/li>\n<li>A TeamCity server. Refer to the\u00a0<a href=\"https:\/\/confluence.jetbrains.com\/display\/TCD10\/Getting+Started+with+TeamCity\" target=\"_blank\" rel=\"noopener\">Getting Started<\/a>\u00a0guide for details.<\/li>\n<\/ul>\n<p>Perform the following:<\/p>\n<ul>\n<li>Download the plugin from the <a href=\"https:\/\/plugins.jetbrains.com\/plugin\/10011-hashicorp-vault-support\" target=\"_blank\" rel=\"noopener\">plugin repository<\/a>, and <a href=\"https:\/\/confluence.jetbrains.com\/display\/TCD10\/Installing+Additional+Plugins\" target=\"_blank\" rel=\"noopener\">install<\/a>\u00a0it to TeamCity server.<\/li>\n<li>Configure <a href=\"https:\/\/www.vaultproject.io\/docs\/secrets\/\" target=\"_blank\" rel=\"noopener\">secret backends<\/a> in Vault to obtain secrets, for example <a href=\"https:\/\/www.vaultproject.io\/docs\/secrets\/aws\/\" target=\"_blank\" rel=\"noopener\">AWS credentials<\/a>, or <a href=\"https:\/\/www.vaultproject.io\/docs\/secrets\/generic\/\" target=\"_blank\" rel=\"noopener\">generic secrets<\/a>.<\/li>\n<li>Create an <a href=\"https:\/\/www.vaultproject.io\/docs\/auth\/approle.html\" target=\"_blank\" rel=\"noopener\">AppRole<\/a> in Vault for the TeamCity server to access these backends.<\/li>\n<li>Create a connection to Vault in your TeamCity project:<a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-1.png\" rel=\"attachment wp-att-6118\"><img decoding=\"async\" loading=\"lazy\" class=\"alignleft size-full wp-image-6118\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-1.png\" alt=\"1\" width=\"1290\" height=\"752\" \/><\/a><\/li>\n<li style=\"text-align: left;\">Next, in your build configuration declare new build parameters which refer to the Vault secrets to be used in this build:<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\"><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-2.png\" rel=\"attachment wp-att-6119\"><img decoding=\"async\" loading=\"lazy\" class=\"alignleft size-full wp-image-7448\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-screenshot_17334.png\" alt=\"screenshot_17334\" width=\"1202\" height=\"736\" \/><\/a><\/p>\n<p style=\"padding-left: 30px;\">The parameter value has a special <code>syntax:%vault:PATH!KEY%<\/code> where <code>PATH<\/code> is the secret name, and <code>KEY<\/code> is the specific value inside. <strong>If you use <a href=\"https:\/\/www.vaultproject.io\/docs\/secrets\/kv\/kv-v2#upgrading-from-version-1\" target=\"_blank\" rel=\"noopener\">version 2 kv<\/a>, make sure to adjust the path value to <code>%vault:aws\/data\/creds\/deploy!\/access_key%<\/code>.<\/strong><br \/>\n<i>At the moment these values can be used in the build parameter declaration only, and cannot be specified in build steps.<\/i><\/p>\n<ul>\n<li>Run a build step. Deployment scripts can read credentials from environment variables, and do not need to perform any Vault-related actions:<a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-3.png\" rel=\"attachment wp-att-6120\"><img decoding=\"async\" loading=\"lazy\" class=\"alignleft size-full wp-image-6120\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-3.png\" alt=\"3\" width=\"1278\" height=\"702\" \/><\/a><\/li>\n<\/ul>\n<p>Besides AWS, any other Vault backends can be used. In this case:<\/p>\n<ul>\n<li>Declare a configuration parameter with a value from generic backend. <strong>If you use <a href=\"https:\/\/www.vaultproject.io\/docs\/secrets\/kv\/kv-v2#upgrading-from-version-1\" target=\"_blank\" rel=\"noopener\">version 2 kv<\/a>, make sure to adjust the path value to <code>%vault:secret\/data\/foo!\/password%<\/code>.<\/strong><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-4.png\" rel=\"attachment wp-att-6121\"><img decoding=\"async\" loading=\"lazy\" class=\"alignleft size-full wp-image-7449\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-4-1.png\" alt=\"4\" width=\"1210\" height=\"740\" \/><\/a><\/li>\n<li>In a build step, refer to this parameter explicitly:<a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-5.png\" rel=\"attachment wp-att-6122\"><img decoding=\"async\" loading=\"lazy\" class=\"alignleft size-full wp-image-6122\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2017\/09\/teamcity-5.png\" alt=\"5\" width=\"1420\" height=\"686\" \/><\/a><\/li>\n<\/ul>\n<h3>How It Works<\/h3>\n<ul>\n<li>The TeamCity server stores the AppRole ID and secret, and keeps the secret encrypted at rest. When required, it can be rotated manually in the UI, or via the REST API.<\/li>\n<li>When a new build is started, the TeamCity server requests a one-time <a href=\"https:\/\/www.vaultproject.io\/docs\/concepts\/response-wrapping.html\" target=\"_blank\" rel=\"noopener\">response wrapping<\/a>token in Vault, and sends it to a build agent.<br \/>\n<i>The AppRole secret never leaves the TeamCity server machine.<\/i><\/li>\n<li>The build agent requests the actual secrets from Vault.<i><br \/>\nThe actual credentials are obtained from Vault by a build agent machine directly, and never transferred to the TeamCity server.<\/i><\/li>\n<li>The build parameters are resolved and the secrets are passed to environment variables and system properties.<\/li>\n<li>The build steps are started, and they refer to these environment variables and system properties.<\/li>\n<li>If secret values appear in a build log, they are automatically replaced by asterisks.<\/li>\n<li>Right after the build finish, the credentials are explicitly revoked in Vault.<\/li>\n<\/ul>\n<h3><\/h3>\n<h3>Security Considerations<\/h3>\n<p>It is advised that you limit access to TeamCity project settings. If a person can modify build configuration settings in a TeamCity project, they can get access to the secrets. Dynamic credentials are revoked after a build, but for generic secrets this may cause more risks. To minimize the risks, split build configurations for CI and deployments into separate projects with different permissions.<\/p>\n<p>Make sure build agent machines are connected to the TeamCity server via HTTPS. Only one-time tokens are transferred over network, and if they are stolen, credentials will be immediately revoked. However, it is a good practice to encrypt all traffic between the server and agents.<\/p>\n<h2>Feedback Wanted<\/h2>\n<p>This is an initial release, and we continue to improve features and user experience, and encourage you to give it a try and tell us what do you think!<\/p>\n<p>The plugin is open-sourced, and published on <a href=\"https:\/\/github.com\/JetBrains\/teamcity-hashicorp-vault-plugin\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>.<\/p>\n<p>If you are attending <a href=\"https:\/\/www.hashiconf.com\/\" target=\"_blank\" rel=\"noopener\">HashiConf<\/a>\u00a0in Austin, TX, USA next week, visit the JetBrains sponsor booth for the demonstration of this plugin and our other plugins for integrating Packer and Terraform with TeamCity and IntelliJ-based IDEs.<\/p>\n","protected":false},"author":242,"featured_media":0,"comment_status":"open","ping_status":"open","template":"","categories":[808,11,1401,601],"tags":[],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/teamcity\/12600"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/teamcity"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/teamcity"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/242"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=12600"}],"version-history":[{"count":2,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/teamcity\/12600\/revisions"}],"predecessor-version":[{"id":232129,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/teamcity\/12600\/revisions\/232129"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=12600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=12600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=12600"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=12600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}