From 778f1ab138da6c235ad7099231d825a2d84e932c Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Tue, 4 Feb 2020 06:30:40 -1000 Subject: [PATCH] website: Documentation for the "terraform login" command (#22727) Co-authored-by: Alisdair McDiarmid --- website/docs/backends/types/remote.html.md | 7 +- .../docs/commands/cli-config.html.markdown | 101 ++++++++--- website/docs/commands/login.html.markdown | 45 +++++ .../internals/credentials-helpers.html.md | 171 ++++++++++++++++++ .../internals/login-protocol.html.markdown | 114 ++++++++++++ .../remote-service-discovery.html.md | 3 +- website/layouts/docs.erb | 12 ++ 7 files changed, 423 insertions(+), 30 deletions(-) create mode 100644 website/docs/commands/login.html.markdown create mode 100644 website/docs/internals/credentials-helpers.html.md create mode 100644 website/docs/internals/login-protocol.html.markdown diff --git a/website/docs/backends/types/remote.html.md b/website/docs/backends/types/remote.html.md index 1c6daa64d..a27dfdad5 100644 --- a/website/docs/backends/types/remote.html.md +++ b/website/docs/backends/types/remote.html.md @@ -22,8 +22,6 @@ Cloud's run environment, with log output streaming to the local terminal. Remote Terraform Cloud can also be used with local operations, in which case only state is stored in the Terraform Cloud backend. - - ## Command Support Currently the remote backend supports the following Terraform commands: @@ -172,8 +170,9 @@ The following configuration options are supported: * `organization` - (Required) The name of the organization containing the targeted workspace(s). * `token` - (Optional) The token used to authenticate with the remote backend. - We recommend omitting the token from the configuration, and instead setting it - as `credentials` in the + We recommend omitting the token from the configuration, and instead using + [`terraform login`](/docs/commands/login.html) or manually configuring + `credentials` in the [CLI config file](/docs/commands/cli-config.html#credentials). * `workspaces` - (Required) A block specifying which remote workspace(s) to use. The `workspaces` block supports the following keys: diff --git a/website/docs/commands/cli-config.html.markdown b/website/docs/commands/cli-config.html.markdown index 331169862..fd4e9a552 100644 --- a/website/docs/commands/cli-config.html.markdown +++ b/website/docs/commands/cli-config.html.markdown @@ -63,35 +63,86 @@ The following settings can be set in the CLI configuration file: [plugin caching](/docs/configuration/providers.html#provider-plugin-cache) and specifies, as a string, the location of the plugin cache directory. -- `credentials` — provides credentials for use with Terraform Cloud. - Terraform uses this when performing remote operations or state access with - the [remote backend](../backends/types/remote.html) and when accessing - Terraform Cloud's [private module registry.](/docs/cloud/registry/index.html) +- `credentials` - configures credentials for use with Terraform Cloud or + Terraform Enterprise. See [Credentials](#credentials) below for more + information. - This setting is a repeatable block, where the block label is a hostname - (either `app.terraform.io` or the hostname of a Terraform Enterprise instance) and - the block body contains a `token` attribute. Whenever Terraform accesses - state, modules, or remote operations from that hostname, it will - authenticate with that API token. +- `credentials_helper` - configures an external helper program for the storage + and retrieval of credentials for Terraform Cloud or Terraform Enterprise. + See [Credentials Helpers](#credentials-helpers) below for more information. - ``` hcl - credentials "app.terraform.io" { - token = "xxxxxx.atlasv1.zzzzzzzzzzzzz" - } - ``` +## Credentials - ~> **Important:** The token provided here must be a - [user token](/docs/cloud/users-teams-organizations/users.html#api-tokens) - or a - [team token](/docs/cloud/users-teams-organizations/api-tokens.html#team-api-tokens); - organization tokens cannot be used for command-line Terraform actions. +[Terraform Cloud](/docs/cloud/index.html) provides a number of remote network +services for use with Terraform, and +[Terraform Enterprise](/docs/enterprise/index.html) allows hosting those +services inside your own infrastructure. For example, these systems offer both +[remote operations](/docs/cloud/run/cli.html) and a +[private module registry](/docs/cloud/registry/index.html). - -> **Note:** The credentials hostname must match the hostname in your module - sources and/or backend configuration. If your Terraform Enterprise instance - is available at multiple hostnames, use one of them consistently. (The SaaS - version of Terraform Cloud responds to API calls at both its current - hostname, app.terraform.io, and its historical hostname, - atlas.hashicorp.com.) +When interacting with Terraform-specific network services, Terraform expects +to find API tokens in CLI configuration files in `credentials` blocks: + +```hcl +credentials "app.terraform.io" { + token = "xxxxxx.atlasv1.zzzzzzzzzzzzz" +} +``` + +You can have multiple `credentials` blocks if you regularly use services from +multiple hosts. Many users will configure only one, for either +Terraform Cloud (at `app.terraform.io`) or for their organization's own +Terraform Enterprise host. Each `credentials` block contains a `token` argument +giving the API token to use for that host. + +~> **Important:** If you are using Terraform Cloud or Terraform Enterprise, +the token provided must be either a +[user token](/docs/cloud/users-teams-organizations/users.html#api-tokens) +or a +[team token](/docs/cloud/users-teams-organizations/api-tokens.html#team-api-tokens); +organization tokens cannot be used for command-line Terraform actions. + +-> **Note:** The credentials hostname must match the hostname in your module +sources and/or backend configuration. If your Terraform Enterprise instance +is available at multiple hostnames, use only one of them consistently. +Terraform Cloud responds to API calls at both its current hostname +`app.terraform.io`, and its historical hostname `atlas.hashicorp.com`. + +If you are running the Terraform CLI interactively on a computer that is capable +of also running a web browser, you can optionally obtain credentials and save +them in the CLI configuration automatically using +[the `terraform login` command](./login.html). + +### Credentials Helpers + +If you would prefer not to store your API tokens directly in the CLI +configuration as described in the previous section, you can optionally instruct +Terraform to use a different credentials storage mechanism by configuring a +special kind of plugin program called a _credentials helper_. + +```hcl +credentials_helper "example" { + args = [] +} +``` + +`credentials_helper` is a configuration block that can appear at most once +in the CLI configuration. Its label (`"example"` above) is the name of the +credentials helper to use. The `args` argument is optional and allows passing +additional arguments to the helper program, for example if it needs to be +configured with the address of a remote host to access for credentials. + +A configured credentials helper will be consulted only to retrieve credentials +for hosts that are _not_ explicitly configured in a `credentials` block as +described in the previous section. +Conversely, this means you can override the credentials returned by the helper +for a specific hostname by writing a `credentials` block alongside the +`credentials_helper` block. + +Terraform does not include any credentials helpers in the main distribution. +To learn how to write and install your own credentials helpers to integrate +with existing in-house credentials management systems, see +[the guide to Credentials Helper internals](/docs/internals/credentials-helpers.html). ## Deprecated Settings diff --git a/website/docs/commands/login.html.markdown b/website/docs/commands/login.html.markdown new file mode 100644 index 000000000..085781f54 --- /dev/null +++ b/website/docs/commands/login.html.markdown @@ -0,0 +1,45 @@ +--- +layout: "docs" +page_title: "Command: login" +sidebar_current: "docs-commands-login" +description: |- + The terraform login command can be used to automatically obtain and save an API token for Terraform Cloud, Terraform Enterprise, or any other host that offers Terraform services. +--- + +# Command: login + +The `terraform login` command can be used to automatically obtain and save an +API token for Terraform Cloud, Terraform Enterprise, or any other host that offers Terraform services. + +-> **Note:** This command is suitable only for use in interactive scenarios +where it is possible to launch a web browser on the same host where Terraform +is running. If you are running Terraform in an unattended automation scenario, +you can +[configure credentials manually in the CLI configuration](https://www.terraform.io/docs/commands/cli-config.html#credentials). + +## Usage + +Usage: `terraform login [hostname]` + +If you don't provide an explicit hostname, Terraform will assume you want to +log in to Terraform Cloud at `app.terraform.io`. + +## Credentials Storage + +By default, Terraform will obtain an API token and save it in plain text in a +local CLI configuration file called `credentials.tfrc.json`. When you run +`terraform login`, it will explain specifically where it intends to save +the API token and give you a chance to cancel if the current configuration is +not as desired. + +If you don't wish to store your API token in the default location, you can +optionally configure a +[credentials helper program](cli-config.html#credentials-helpers) which knows +how to store and later retrieve credentials in some other system, such as +your organization's existing secrets management system. + +## Login Server Support + +The `terraform login` command works with any server supporting the +[login protocol](/docs/internals/login-protocol.html), including Terraform Cloud +and Terraform Enterprise. diff --git a/website/docs/internals/credentials-helpers.html.md b/website/docs/internals/credentials-helpers.html.md new file mode 100644 index 000000000..c599c2b18 --- /dev/null +++ b/website/docs/internals/credentials-helpers.html.md @@ -0,0 +1,171 @@ +--- +layout: "docs" +page_title: "Credentials Helpers" +sidebar_current: "docs-internals-credentials-helpers" +description: |- + Credentials helpers are external programs that know how to store and retrieve API tokens for remote Terraform services. +--- + +# Credentials Helpers + +For Terraform-specific features that interact with remote network services, +such as [module registries](/docs/registry/) and +[remote operations](/docs/cloud/run/cli.html), Terraform by default looks for +API credentials to use in these calls in +[the CLI configuration](/docs/commands/cli-config.html). + +Credentials helpers offer an alternative approach that allows you to customize +how Terraform obtains credentials using an external program, which can then +directly access an existing secrets management system in your organization. + +This page is about how to write and install a credentials helper. To learn +how to configure a credentials helper that was already installed, see +[the CLI config Credentials Helpers section](/docs/commands/cli-config.html#credentials-helpers). + +## How Terraform finds Credentials Helpers + +A credentials helper is a normal executable program that is installed in a +particular location and whose name follows a specific naming convention. + +A credentials helper called "credstore", for example, would be implemented as +an executable program named `terraform-credentials-credstore` (with an `.exe` +extension on Windows only), and installed in one of the +[default plugin search locations](/docs/extend/how-terraform-works.html#plugin-locations). + +## How Terraform runs Credentials Helpers + +Once Terraform has located the configured credentials helper, it will execute +it once for each credentials request that cannot be satisfied by a `credentials` +block in the CLI configuration. + +For the following examples, we'll assume a "credstore" credentials helper +configured as follows: + +``` +credentials_helper "credstore" { + args = ["--host=credstore.example.com"] +} +``` + +Terraform runs the helper program with each of the arguments given in `args`, +followed by an _verb_ and then the hostname that the verb will apply to. +The current set of verbs are: + +* `get`: retrieve the credentials for the given hostname +* `store`: store new credentials for the given hostname +* `forget`: delete any stored credentials for the given hostname + +To represent credentials, the credentials helper protocol uses a JSON object +whose contents correspond with the contents of +[`credentials` blocks in the CLI configuration](/docs/commands/cli-config.html#credentials). +To represent an API token, the object contains a property called "token" whose +value is the token string: + +```json +{ + "token": "example-token-value" +} +``` + +The following sections describe the specific expected behaviors for each of the +three verbs. + +## `get`: retrieve the credentials for the given hostname + +To retrieve credentials for `app.terraform.io`, Terraform would run the +"credstore" helper as follows: + +``` +terraform-credentials-credstore --host=credstore.example.com get app.terraform.io +``` + +If the credentials helper is able to provide credentials for the given host +then it must print a JSON credentials object to its stdout stream and then +exit with status code zero to indicate success. + +If it is unable to provide the requested credentials for any reason, it must +print an end-user-oriented plain text error message to its stderr stream and +then exit with a _non-zero_ status code. + +## `store`: store new credentials for the given hostname + +To store new credentials for `app.terraform.io`, Terraform would run the +"credstore" helper as follows: + +``` +terraform-credentials-credstore --host=credstore.example.com store app.terraform.io +``` + +Terraform then writes a JSON credentials object to the helper program's stdin +stream. If the helper is able to store the given credentials then it must do +so and then exit with status code zero and no output on stdout or stderr to +indicate success. + +If it is unable to store the given credentials for any reason, it _must_ still +fully read its stdin until EOF and then print an end-user-oriented plain text +error message to its stderr stream before exiting with a non-zero status +code. + +The new credentials must fully replace any existing credentials stored for the +given hostname. + +## `forget`: delete any stored credentials for the given hostname + +To forget any existing credentials for `app.terraform.io`, Terraform would run +the "credstore" helper as follows: + +``` +terraform-credentials-credstore --host=credstore.example.com forget app.terraform.io +``` + +No JSON credentials objects are used for the `forget` verb. + +If the helper program is able to delete its stored credentials for the given +hostname or if there are no such credentials stored already then it must +exist with status code zero and produce no output on stdout or stderr. + +If it is unable to forget the stored credentials for any reason, particularly +if the helper cannot be sure that the credentials are no longer available for +retrieval, the helper program must print an end-user-oriented plain text error +message to its stderr stream and then exit with a non-zero status code. + +## Handling Other Commands + +The credentials helper protocol may be extended with additional verbs in future, +so for forward-compatibility a credentials helper must react to any unsupported +verb by printing an end-user-oriented plain text error message to its stderr +stream and then exiting with a non-zero status code. + +## Handling Unsupported Credentials Object Properties + +Currently Terraform defines only the `token` property within JSON credentials +objects, but this format might be extended in future. + +If a credentials helper is asked to store an object that has any properties +other than `token` and if it is not able to faithfully retain them then it +must behave as if the object is unstorable, returning an error. It must _not_ +store the `token` value in isolation and silently drop other properties, as +that might change the meaning of the credentials object. + +If technically possible within the constraints of the target system, a +credentials helper should prefer to store the whole JSON object as-is for +later retrieval. For systems that are more constrained, it's acceptable to +store only the `token` string so long as the program rejects objects containing +other properties as described above. + +## Installing a Credentials Helper + +Terraform does not have any automatic installation mechanism for credentials +helpers. Instead, the user must extract the helper program executable into +one of the [default plugin search locations](/docs/extend/how-terraform-works.html#plugin-locations). + +If you are packaging a credentials helper for distribution, place it in an +named with the expected naming scheme (`terraform-credentials-example`) and, +if the containing archive format supports it and it's meaningful for the +target operating system, mark the file as executable to increase the chances +that it will work immediately after extraction. + +Terraform does _not_ honor the `-plugin-dir` argument to `terraform init` when +searching for credentials helpers, because credentials are also used by other +commands that can be run prior to `terraform init`. Only the default search +locations are supported. diff --git a/website/docs/internals/login-protocol.html.markdown b/website/docs/internals/login-protocol.html.markdown new file mode 100644 index 000000000..560a471be --- /dev/null +++ b/website/docs/internals/login-protocol.html.markdown @@ -0,0 +1,114 @@ +--- +layout: "docs" +page_title: "Login Protocol" +sidebar_current: "docs-internals-login-protocol" +description: |- + The login protocol is used for authenticating Terraform against servers providing Terraform-native services. +--- + +# Server-side Login Protocol + +~> **Note:** You don't need to read these docs to _use_ +[`terraform login`](/docs/commands/login.html). The information below is for +anyone intending to implement the server side of `terraform login` in order to +offer Terraform-native services in a third-party system. + +The `terraform login` command supports performing an OAuth 2.0 authorization +request using configuration provided by the target host. You may wish to +implement this protocol if you are producing a third-party implementation of +any [Terraform-native services](/docs/internals/remote-service-discovery.html), +such as a Terraform module registry. + +First, Terraform uses +[remote service discovery](/docs/internals/remote-service-discovery.html) to +find the OAuth configuration for the host. The host must support the service +name `login.v1` and define for it an object containing OAuth client +configuration values, like this: + +```json +{ + "login.v1": { + "client": "terraform-cli", + "grant_types": ["authz_code"], + "authz": "/oauth/authorization", + "token": "/oauth/token", + "ports": [10000, 10010], + } +} +``` + +The properties within the discovery object are as follows: + +* `client` (Required): The `client_id` value to use when making requests, as + defined in [RFC 6749 section 2.2](https://tools.ietf.org/html/rfc6749#section-2.2). + + Because Terraform is a _public client_ (it is installed on end-user systems + and thus cannot protect an OAuth client secret), the `client_id` is purely + advisory and the server must not use it as a guarantee that an authorization + request is truly coming from Terraform. + +* `grant_types` (Optional): A JSON array of strings describing a set of OAuth + 2.0 grant types the server is able to support. A "grant type" selects a + specific mechanism by which an OAuth server authenticates the request and + issues an authorization token. + + Terraform CLI currently only supports a single grant type: + + * `authz_code`: [authorization code grant](https://tools.ietf.org/html/rfc6749#section-4.1). + Both the `authz` and `token` properties are required when `authz_code` is + present. + + Other grant types may be supported in future versions of Terraform CLI, + and may impose different requirements on the `authz` and `token` properties. + If not specified, `grant_types` defaults to `["authz_code"]`. + +* `authz` (Required if needed for a given grant type): the server's + [authorization endpoint](https://tools.ietf.org/html/rfc6749#section-3.1). + If given as a relative URL, it is resolved from the location of the + service discovery document. + +* `token` (Required if needed for a given grant type): the server's + [token endpoint](https://tools.ietf.org/html/rfc6749#section-3.2). + If given as a relative URL, it is resolved from the location of the + service discovery document. + +* `ports` (Optional): A two-element JSON array giving an inclusive range of + TCP ports that Terraform may use for the temporary HTTP server it will start + to provide the [redirection endpoint](https://tools.ietf.org/html/rfc6749#section-3.1.2) + for the first step of an authorization code grant. Terraform opens a TCP + listen port on the loopback interface in order to receive the response from + the server's authorization endpoint. + + If not specified, Terraform is free to select any TCP port greater than or + equal to 1024. + + Terraform allows constraining this port range for interoperability with OAuth + server implementations that require each `client_id` to be associated with + a fixed set of valid redirection endpoint URLs. Configure such a server + to expect a range of URLs of the form `http://localhost:10000/` + with different consecutive port numbers, and then specify that port range + using `ports`. + + We recommend allowing at least 10 distinct port numbers if possible, and + assigning them to numbers greater than or equal to 10000, to minimize the + risk that all of the possible ports will already be in use on a particular + system. + +When requesting an authorization code grant, Terraform CLI implements the +[Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636) extension in +order to protect against other applications on the system intercepting the +incoming request to the redirection endpoint. We strongly recommend that you +select an OAuth server implementation that also implements this extension and +verifies the code challenge sent to the token endpoint. + +Terraform CLI does not support OAuth refresh tokens or token expiration. If your +server issues time-limited tokens, Terraform CLI will simply begin receiving +authorization errors once the token expires, after which the user can run +`terraform login` again to obtain a new token. + +-> **Note:** As a special case, Terraform can use a +[Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.3) +only when interacting with `app.terraform.io` ([Terraform Cloud](/docs/cloud/index.html)), +under the recommendation in the OAuth specification to use this grant type only +when the client and server are closely related. The `password` grant type is +not supported for any other hostname and will be ignored. diff --git a/website/docs/internals/remote-service-discovery.html.md b/website/docs/internals/remote-service-discovery.html.md index 84ba3c6e0..87e56ba74 100644 --- a/website/docs/internals/remote-service-discovery.html.md +++ b/website/docs/internals/remote-service-discovery.html.md @@ -83,8 +83,9 @@ version 1 of the module registry protocol: ## Supported Services -At present, only one service identifier is in use: +At present, the following service identifiers are in use: +* `login.v1`: [login protocol version 1](/docs/commands/login.html#protocol-v1) * `modules.v1`: [module registry API version 1](/docs/registry/api.html) ## Authentication diff --git a/website/layouts/docs.erb b/website/layouts/docs.erb index f1197097f..a91e2183b 100644 --- a/website/layouts/docs.erb +++ b/website/layouts/docs.erb @@ -186,6 +186,10 @@ init + > + login + + > output @@ -429,6 +433,10 @@ > Internals