Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Nomad secret backend #923

Merged
merged 9 commits into from
Dec 11, 2020
Merged

Add Nomad secret backend #923

merged 9 commits into from
Dec 11, 2020

Conversation

jasonodonnell
Copy link
Contributor

@jasonodonnell jasonodonnell commented Nov 30, 2020

This PR adds support for the Nomad secret engine. The following endpoints are supported.

  • "/nomad/config/access" as a resource
  • "/nomad/config/lease" as a resource
  • "/nomad/role/<role name>" as a resource
  • "/nomad/creds/<role name>" as a data source

Currently automated acceptance testing isn't integrated with CircleCI because to run Nomad in a container, it needs to run as privileged. When we update the CI for other integrated testing (such as AD) this should be added and is being tracked internally.

To manually test this, you can use the following script: https://gist.github.com/jasonodonnell/1a2cfaaa376592c170ad5fa2eab7e423. This script assumes you have vault and nomad installed.

To run the acceptance tests, here's a setup script you can run from the project root: https://gist.github.com/jasonodonnell/e40a9b63eb8e9cd3556d221fd2e16494. This script assumes you have vault and nomad installed.

If you want to test this via terraform binary, here's an example resource:

variable "TOKEN" {}

provider "vault" {
  address = "http://0.0.0.0:8200"
  token = "root"
}

resource "vault_nomad_secret_backend" "config" {
    backend = "nomad"
    address = "http://0.0.0.0:4646"
    token = var.TOKEN
    max_ttl = 60
    ttl = 30
}

resource "vault_nomad_secret_role" "test" {
    backend = vault_nomad_secret_backend.config.backend
    role = "test"
    type = "client"
    policies = ["readonly"]
}

data "vault_nomad_access_token" "token" {
  backend = vault_nomad_secret_backend.config.backend
  role    = vault_nomad_secret_role.test.role
  depends_on = [vault_nomad_secret_role.test]
}

output "secret" {
  value = data.vault_nomad_access_token.token.secret_id
}

output "accessor" {
  value = data.vault_nomad_access_token.token.accessor_id
}
Related test output
[~/Git/terraform-provider-vault] make testacc TESTARGS='-run TestAccDataSourceNomadAccess*'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test $(go list ./... |grep -v 'vendor') -v -run TestAccDataSourceNomadAccess* -timeout 120m
?   	github.com/hashicorp/terraform-provider-vault	[no test files]
?   	github.com/hashicorp/terraform-provider-vault/cmd/coverage	[no test files]
?   	github.com/hashicorp/terraform-provider-vault/cmd/generate	[no test files]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/codegen	(cached) [no tests to run]
?   	github.com/hashicorp/terraform-provider-vault/generated	[no test files]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/datasources/transform/decode	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/datasources/transform/encode	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/alphabet	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/role	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/template	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/transformation	(cached) [no tests to run]
?   	github.com/hashicorp/terraform-provider-vault/schema	[no test files]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/util	(cached) [no tests to run]
=== RUN   TestAccDataSourceNomadAccessCredentialsClientBasic
--- PASS: TestAccDataSourceNomadAccessCredentialsClientBasic (0.73s)
=== RUN   TestAccDataSourceNomadAccessCredentialsManagementBasic
--- PASS: TestAccDataSourceNomadAccessCredentialsManagementBasic (0.71s)
PASS
ok  	github.com/hashicorp/terraform-provider-vault/vault	1.940s

[~/Git/terraform-provider-vault] make testacc TESTARGS='-run TestAccNomadSecret*'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test $(go list ./... |grep -v 'vendor') -v -run TestAccNomadSecret* -timeout 120m
?   	github.com/hashicorp/terraform-provider-vault	[no test files]
?   	github.com/hashicorp/terraform-provider-vault/cmd/coverage	[no test files]
?   	github.com/hashicorp/terraform-provider-vault/cmd/generate	[no test files]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/codegen	(cached) [no tests to run]
?   	github.com/hashicorp/terraform-provider-vault/generated	[no test files]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/datasources/transform/decode	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/datasources/transform/encode	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/alphabet	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/role	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/template	(cached) [no tests to run]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/generated/resources/transform/transformation	(cached) [no tests to run]
?   	github.com/hashicorp/terraform-provider-vault/schema	[no test files]
testing: warning: no tests to run
PASS
ok  	github.com/hashicorp/terraform-provider-vault/util	(cached) [no tests to run]
=== RUN   TestAccNomadSecretLease
--- PASS: TestAccNomadSecretLease (0.21s)
=== RUN   TestAccNomadSecretBackendRoleClientBasic
--- PASS: TestAccNomadSecretBackendRoleClientBasic (0.14s)
=== RUN   TestAccNomadSecretBackendRoleManagementBasic
--- PASS: TestAccNomadSecretBackendRoleManagementBasic (0.14s)
=== RUN   TestAccNomadSecretBackendRoleImport
--- PASS: TestAccNomadSecretBackendRoleImport (0.16s)
PASS
ok  	github.com/hashicorp/terraform-provider-vault/vault	1.118s

Closes #831.

@@ -466,6 +470,18 @@ var (
Resource: ldapAuthBackendGroupResource(),
PathInventory: []string{"/auth/ldap/groups/{name}"},
},
"vault_nomad_secret_backend": {
Resource: nomadSecretAccessBackendResource(),
PathInventory: []string{"/nomad"},
Copy link
Contributor

Choose a reason for hiding this comment

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

Should /nomad/config/access be part of PathInventory here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@calvn Good question! Throughout the provider the mount and the config are the same resource. We derive the full path nomad/config/access from the backend. Since we derive it, /nomad is the default.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nomad/config/lease is slightly different so I didn't add it to this resource. We could but it felt different enough to have a separate resource.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@calvn Having thought about combining nomad/config/lease with the other configs, I decided to keep them as two separate resources. This is simply to reduce the amount of operations create/update/read need to do for all three paths (/nomad, /nomad/config/access and /nomad/config/lease).

Copy link
Member

Choose a reason for hiding this comment

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

Is PathInventory used for routing? Or is is just for documentation purposes?

To Calvin's question this function does seem to cover the /nomad/config/access endpoint?

Copy link
Contributor Author

@jasonodonnell jasonodonnell Dec 2, 2020

Choose a reason for hiding this comment

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

I can try in the morning having both but pointing to the same resource handler, maybe that won't cause issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update: both can't be present because the resource name is the key and you can't duplicate it.

I changed the PathInventory to be /nomad/config/access. This did not have any regressions on the resources and is probably a better self-documenting change.

Copy link
Member

Choose a reason for hiding this comment

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

PathInventory is a list, so it could also be this:

		"vault_nomad_secret_backend": {
			Resource:      nomadSecretAccessBackendResource(),
			PathInventory: []string{
				"/nomad",
				"/nomad/config/access",
			},

But I think setting it to just "/nomad/config/access" makes sense 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh derp, yeah, that did work! Good call!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

/nomad, /nomad/config/access and /nomad/config/lease are merged into a single resource vault_nomad_secret_backend.

Copy link
Member

@tvoran tvoran left a comment

Choose a reason for hiding this comment

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

The manual and acceptance tests worked for me locally, not seeing any blockers on the first pass here.

vault/resource_nomad_secret_backend.go Outdated Show resolved Hide resolved
vault/resource_nomad_secret_role.go Outdated Show resolved Hide resolved
@@ -466,6 +470,18 @@ var (
Resource: ldapAuthBackendGroupResource(),
PathInventory: []string{"/auth/ldap/groups/{name}"},
},
"vault_nomad_secret_backend": {
Resource: nomadSecretAccessBackendResource(),
PathInventory: []string{"/nomad"},
Copy link
Member

Choose a reason for hiding this comment

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

Is PathInventory used for routing? Or is is just for documentation purposes?

To Calvin's question this function does seem to cover the /nomad/config/access endpoint?

vault/provider.go Outdated Show resolved Hide resolved
return fmt.Errorf("secret_id is not set in response")
}

d.SetId(accessorID)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use path here? Granted, we aren't using the ID at all that I can see

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Each call to this endpoint generates a new token, so we want the ID to be the unique identifier of that specific generated token. Path would be too generic I think?

return nil
}

if val, ok := resp.Data["address"]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these values should be read and update the state regardless if they are set in the response. If we use this resource to set them, and then out-of-band the backend is destroyed and recreated at the same address but without these values, we'll fail to detect the drift here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is Required: true, so you would get an error if you didn't set it. Thoughts?

tune := api.MountConfigInput{}
data := map[string]interface{}{}

if defaultTTL != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this prevents us from initially setting a default lease to something that is not the default system lease, and then removing it, e.g. we can't set it to something non-standard and then try to later adapt the system defaults implicitly by removing our non-standard value.

Example:

  • System default is 5m
  • We use default_lease_ttl_seconds to set it to 6m instead
  • Later we decide we want to use the system defaults, so we remove our default_lease_ttl_seconds
  • No change is detected here, because the new value would be the zero value, right?
  • No update happens, and the default least ttl remains at 6m

Is my assumption correct here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, fixed.

@jasonodonnell jasonodonnell merged commit 00b8dd3 into master Dec 11, 2020
@jasonodonnell jasonodonnell deleted the nomad-backend branch December 11, 2020 14:46
dandandy pushed a commit to dandandy/terraform-provider-vault that referenced this pull request Jun 17, 2021
* Add Nomad secret backend

* Update vault/resource_nomad_secret_backend.go

Co-authored-by: Theron Voran <[email protected]>

* Update vault/resource_nomad_secret_role.go

Co-authored-by: Theron Voran <[email protected]>

* Change PathInventory to config/access

* Add more paths to inventory

* Merge lease config with backend resource

* Fix updating mount parameters

* Remove required flag from token/address

* Remove commented code

Co-authored-by: Theron Voran <[email protected]>
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.

4 participants