Skip to content

Machine ID: Terraform Cloud joining#45574

Merged
timothyb89 merged 21 commits intomasterfrom
timothyb89/terraform-cloud-joining
Aug 27, 2024
Merged

Machine ID: Terraform Cloud joining#45574
timothyb89 merged 21 commits intomasterfrom
timothyb89/terraform-cloud-joining

Conversation

@timothyb89
Copy link
Copy Markdown
Contributor

@timothyb89 timothyb89 commented Aug 17, 2024

This adds a new terraform join method, which uses Terraform Cloud's Workload Identity OIDC provider to provide delegated joining support for Machine ID bots. As the Terraform provider now embeds tbot, this means - with some light modifications - that the Terraform provider can now join using this join method, and without any secrets.

Short instruction doc: https://gist.github.com/timothyb89/5bb905e8c7065ae0601e83f816af8056

changelog: Add new terraform join method to allow secretless authentication for Terraform Cloud jobs in the Teleport Terraform provider


Separate docs PR (WIP): #45806

This adds a new `terraform` join method, which uses Terraform Cloud's
Workload Identity OIDC provider to provide delegated joining support
for Machine ID bots. As the Terraform provider now embeds tbot, this
means - with some light modifications - that the Terraform provider
can now join using this join method, and without any secrets.
@timothyb89 timothyb89 requested a review from strideynet August 17, 2024 01:09

// Audience is the JWT audience as configured in the
// TFC_WORKLOAD_IDENTITY_AUDIENCE(_$TAG) variable in Terraform Cloud.
string Audience = 2 [(gogoproto.jsontag) = "audience,omitempty"];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have it so that we always just expect the audience to equal the name of the Teleport cluster ? That sounds more semantically correct to me.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, and I think that's the only answer we could bake in that makes sense. It might make the config/docs UX a bit weird (without a guided flow of some sort at least) but is otherwise fine.

The more confusing parameter is the $TAG, I suppose. For docs purposes we can just recommend TFC_WORKLOAD_IDENTITY_AUDIENCE_TELEPORT=<cluster name>.

Do you think that should be the default value if unset, or should we just always use the cluster name? Is there any sane usecase for allowing user override?

Comment thread api/types/provisioning.go

for i, allowRule := range a.Allow {
orgSet := allowRule.OrganizationID != "" || allowRule.OrganizationName != ""
projectSet := allowRule.ProjectID != "" || allowRule.ProjectName != ""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are project names globally unique across TfCloud ? We should ensure we require at least one globally unique property here.

Copy link
Copy Markdown
Contributor Author

@timothyb89 timothyb89 Aug 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Organization names/ids are, at least. The others are only unique within their parent org/project. I think we could require that at least organization (name or ID) is set, then at least one of project name/project ID/workspace name/workspace ID?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I think I've done similar on another one of the join methods (always required org id/org name). Without it, it's super easy to make a join token that would allow a bad actor to create their own org, create a project w/ the same name, and access your cluster.

func (its *IDTokenSource) GetIDToken() (string, error) {
name := "TFC_WORKLOAD_IDENTITY_TOKEN"
if its.audienceTag != "" {
name = fmt.Sprintf("TFC_WORKLOAD_IDENTITY_TOKEN_%s", strings.ToUpper(its.audienceTag))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow - had no clue they put the audience into the name of the env var - that's super awkward!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it's a weird one. Well, not quite in the name of the var - the audience tag is an optional parameter in the var name. The audience is the var value.

The rule is more or less: whenever TFC sees a var matching TFC_WORKLOAD_IDENTITY_AUDIENCE(?P<tag>_\w+)? during a run, it uses the value as the audience, then writes the JWT into $TFC_WORKLOAD_IDENTITY_TOKEN$tag.

The tag is meant to let you issue more than one token, since otherwise you could only define one audience. More docs here: https://developer.hashicorp.com/terraform/enterprise/workspaces/dynamic-provider-credentials/specifying-multiple-configurations


(Naturally, none of this applies to their own providers which use some slightly different magic to write the same content into different env vars 🤷)

Comment thread lib/auth/join_terraform.go
This addresses a few feedback items, defaulting the audience to the
Teleport cluster name and requiring allow rules specify an
organization + at least one other parameter.

Also, adds a first batch of tests.
@timothyb89 timothyb89 marked this pull request as ready for review August 21, 2024 01:32
@github-actions
Copy link
Copy Markdown
Contributor

The PR changelog entry failed validation: Changelog entry not found in the PR body. Please add a "no-changelog" label to the PR, or changelog lines starting with changelog: followed by the changelog entries for the PR.

@public-teleport-github-review-bot
Copy link
Copy Markdown

@timothyb89 - this PR will require admin approval to merge due to its size. Consider breaking it up into a series smaller changes.

@github-actions
Copy link
Copy Markdown
Contributor

🤖 Vercel preview here: https://docs-368e171r4-goteleport.vercel.app/docs/ver/preview

@github-actions
Copy link
Copy Markdown
Contributor

🤖 Vercel preview here: https://docs-lzdcdb8sb-goteleport.vercel.app/docs/ver/preview

@mgriffin13
Copy link
Copy Markdown

FWIW, I'd imagine this same solution would be used for Terraform Enterprise (the self-hosted version of TFC). Not sure that's enough to preclude a name change, but it might be worth mentioning in the docs at least.
https://developer.hashicorp.com/terraform/enterprise/workspaces/dynamic-provider-credentials/workload-identity-tokens

The docs aren't super clear here so I think we'd need to work with a customer running Terraform Enterprise to test it, but this should be a reasonably simple addition we can make in a followup. It looks like the issuer for Enterprise will just be the self hosted cluster, so we'll just make that URL configurable on our end (as part of the provision token).

In terms of naming, I think it'll be less weird to use a terraform_cloud-type token with an overridden issuer than to keep it named just terraform, which I think already creates confusion between non-cloud Terraform users and our own Terraform provider.

Thanks. I'm excited for this, because this is blocking my upgrade to Teleport v16+ after the change that required MFA for every local user, and I'm using Terraform Enterprise, which is why I'm curious about compatibility.

@timothyb89
Copy link
Copy Markdown
Contributor Author

Thanks. I'm excited for this, because this is blocking my upgrade to Teleport v16+ after the change that required MFA for every local user, and I'm using Terraform Enterprise, which is why I'm curious about compatibility.

@mgriffin13, if you'd be up for testing out early builds, feel free to reach out to me on our community Slack! I'd like to follow up quickly with support for Terraform Enterprise but don't have a way of testing it myself at the moment. If things go well, I think we should be able to get everything into v16.3.

@github-actions
Copy link
Copy Markdown
Contributor

🤖 Vercel preview here: https://docs-7d5on2n3a-goteleport.vercel.app/docs/ver/preview

@timothyb89 timothyb89 added this pull request to the merge queue Aug 27, 2024
Merged via the queue into master with commit 03dba13 Aug 27, 2024
@timothyb89 timothyb89 deleted the timothyb89/terraform-cloud-joining branch August 27, 2024 23:44
@public-teleport-github-review-bot
Copy link
Copy Markdown

@timothyb89 See the table below for backport results.

Branch Result
branch/v16 Failed

timothyb89 added a commit that referenced this pull request Aug 30, 2024
Backport of #45574 for branch/v16

---

* Machine ID: Terraform Cloud joining

This adds a new `terraform` join method, which uses Terraform Cloud's
Workload Identity OIDC provider to provide delegated joining support
for Machine ID bots. As the Terraform provider now embeds tbot, this
means - with some light modifications - that the Terraform provider
can now join using this join method, and without any secrets.

* Address some review feedback, add first batch of tests

This addresses a few feedback items, defaulting the audience to the
Teleport cluster name and requiring allow rules specify an
organization + at least one other parameter.

Also, adds a first batch of tests.

* Update autogenerated CRD docs

* Add tests for RegisterUsingToken and provisioning token init

* Fix imports

* Fix CRD docs

* Update tfschema

* Update tf docs

* Update docstring to make it clear that `Audience` is optional

* Update manifests

* Update CRD docs

* Code review feedback; docstring fixes

* Rename lib/terraform to lib/terraformcloud

* Rename terraform -> terraform_cloud

Renames the new join method to terraform_cloud to make it clear that
it won't work for TF running elsewhere (where other join methods
should be used)

* Fix tests and docs lints

* Update api/proto/teleport/legacy/types/types.proto

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

* Update proto artifacts

---------

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>
timothyb89 added a commit that referenced this pull request Aug 30, 2024
This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.
@timothyb89
Copy link
Copy Markdown
Contributor Author

timothyb89 commented Sep 6, 2024

Support for Terraform Enterprise is in progress here: #46051

github-merge-queue Bot pushed a commit that referenced this pull request Sep 10, 2024
This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.
github-merge-queue Bot pushed a commit that referenced this pull request Sep 12, 2024
* Terraform Cloud joining: Support Terraform Enterprise issuers

This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.

* Enable Terraform Cloud joining for Teleport Community Edition

This enables Terraform Cloud joining for Community Edition when
using the public HCP Terraform SaaS. Teleport Enterprise is still
required for use with self-hosted Terraform Enterprise.

changelog: Enable Terraform Cloud joining for Teleport Community Edition when using HCP Terraform

* Fix unit tests

* Update lib/auth/join_terraformcloud.go

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

* Fix linter

---------

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>
timothyb89 added a commit that referenced this pull request Sep 13, 2024
This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.
timothyb89 added a commit that referenced this pull request Sep 13, 2024
* Terraform Cloud joining: Support Terraform Enterprise issuers

This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.

* Enable Terraform Cloud joining for Teleport Community Edition

This enables Terraform Cloud joining for Community Edition when
using the public HCP Terraform SaaS. Teleport Enterprise is still
required for use with self-hosted Terraform Enterprise.

changelog: Enable Terraform Cloud joining for Teleport Community Edition when using HCP Terraform

* Fix unit tests

* Update lib/auth/join_terraformcloud.go

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

* Fix linter

---------

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>
github-merge-queue Bot pushed a commit that referenced this pull request Sep 18, 2024
* Machine ID: Terraform Cloud joining (#45574)

Backport of #45574 for branch/v16

---

* Machine ID: Terraform Cloud joining

This adds a new `terraform` join method, which uses Terraform Cloud's
Workload Identity OIDC provider to provide delegated joining support
for Machine ID bots. As the Terraform provider now embeds tbot, this
means - with some light modifications - that the Terraform provider
can now join using this join method, and without any secrets.

* Address some review feedback, add first batch of tests

This addresses a few feedback items, defaulting the audience to the
Teleport cluster name and requiring allow rules specify an
organization + at least one other parameter.

Also, adds a first batch of tests.

* Update autogenerated CRD docs

* Add tests for RegisterUsingToken and provisioning token init

* Fix imports

* Fix CRD docs

* Update tfschema

* Update tf docs

* Update docstring to make it clear that `Audience` is optional

* Update manifests

* Update CRD docs

* Code review feedback; docstring fixes

* Rename lib/terraform to lib/terraformcloud

* Rename terraform -> terraform_cloud

Renames the new join method to terraform_cloud to make it clear that
it won't work for TF running elsewhere (where other join methods
should be used)

* Fix tests and docs lints

* Update api/proto/teleport/legacy/types/types.proto

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

* Update proto artifacts

---------

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

* Terraform Cloud joining: Support Terraform Enterprise issuers (#46051)

This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.

* Enable Terraform Cloud joining for Teleport Community Edition (#46419)

* Terraform Cloud joining: Support Terraform Enterprise issuers

This adds support for hostname/issuer overrides, needed to support
on-prem Terraform Enterprise installs. When the new `hostname` field
is unset, behavior is changed, but when set, the JWT is validated
against it instead of `app.terraform.io`.

Additionally, this renames `join_terraform.go` to
`join_terraformcloud.go`, since that was missed during the rename
in #45574.

* Enable Terraform Cloud joining for Teleport Community Edition

This enables Terraform Cloud joining for Community Edition when
using the public HCP Terraform SaaS. Teleport Enterprise is still
required for use with self-hosted Terraform Enterprise.

changelog: Enable Terraform Cloud joining for Teleport Community Edition when using HCP Terraform

* Fix unit tests

* Update lib/auth/join_terraformcloud.go

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

* Fix linter

---------

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>

---------

Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants