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 resources for Vault Identity Tokens #488

Merged
merged 9 commits into from
Aug 8, 2019

Conversation

lawliet89
Copy link
Contributor

@lawliet89 lawliet89 commented Aug 5, 2019

  • Add vault_identity_oidc_key
  • Add vault_identity_oidc_role resource
  • Add vault_identity_oidc resource
  • Add vault_identity_oidc_key_allowed_client_id

The name for the last resource might be a bit too long... 😅

- Add `vault_identity_oidc_key`
- Add `vault_identity_oidc_role` resource
- Add `vault_identity_oidc` resource

- Add `vault_identity_oidc_key_allowed_client_id`
@tyrannosaurus-becks tyrannosaurus-becks self-assigned this Aug 5, 2019
@kalafut kalafut self-assigned this Aug 5, 2019
Copy link
Contributor

@tyrannosaurus-becks tyrannosaurus-becks left a comment

Choose a reason for hiding this comment

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

Generally speaking, this is looking very good! Just a couple questions here and there.

util/util.go Outdated Show resolved Hide resolved
util/util.go Show resolved Hide resolved
util/util.go Show resolved Hide resolved
vault/provider.go Outdated Show resolved Hide resolved
vault/provider.go Show resolved Hide resolved
vault/resource_identity_oidc_role.go Show resolved Hide resolved
@lawliet89
Copy link
Contributor Author

lawliet89 commented Aug 6, 2019

Hi @tyrannosaurus-becks. I will answer several of your questions in a comment since they are mostly related.

Client IDs

The steps to use an Identity Token Role involve:

  1. Creating a Named key (vault_identity_oidc_key). When creating the key, you can either configure the allowed_client_ids to be ["*"] and skip step 3 later, or leave it empty for now.
  2. Create a Role (vault_identity_oidc_role). Upon creation, Vault will generate a client_id which is a Computed only argument in the resource.
  3. You will need to go back to the named key and add the generated client_id into the list of allowed_client_ids.

As you can see that there is a circular dependency here. You cannot know the client_id from a Role since it's computed and generated by Vault. But the role requires a Named Key and the Named Key needs a list of allowed_client_ids. Thus, I "invented" the vault_identity_oidc_key_allowed_client_id to allow us to decouple the adding of the client_id of the role to the key after it's been created.

The example code below and also written in the documentation should demonstrate what I mean:

resource "vault_identity_oidc_key" "key" {
  name      = "key"
  algorithm = "RS256"
}

resource "vault_identity_oidc_role" "role" {
  name = "role"
  key  = vault_identity_oidc_key.key.name
}

resource "vault_identity_oidc_key_allowed_client_id" "role" {
  key_name          = vault_identity_oidc_key.key.name
  allowed_client_id = vault_identity_oidc_role.role.client_id
}

Mutex

The issue now is that we cannot have both vault_identity_oidc_key and vault_identity_oidc_key_allowed_client_id resources write to the same key at the same time. Thus, I have the following code in functions that write to the key:

vaultMutexKV.Lock(path)
defer vaultMutexKV.Unlock(path)

where the path is the path to the named key in Vault.

This pattern is first used in the AWS Provider for resources like aws_security_group and aws_security_group_rule resources. The AWS Security groups also have the same issue in that the authors wanted to allow decoupled declaration of rules but AWS only has one single API resource for rules and security group.

The AWS Provider also declares a global provider KV Mutex which is what I did here. I intend the key of the global KV mutex to be the Vault Path for resources if they need to use it.

Hope this answers your questions.

Copy link
Contributor

@tyrannosaurus-becks tyrannosaurus-becks left a comment

Choose a reason for hiding this comment

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

Thank you @lawliet89 for this PR and for the explanations!

This looks great to me. I'm going to hold on merging it in case my colleague Jim wants to also provide input, since he also self-assigned reviewing this PR. However, barring any blockers, I will make sure to get this merged so it can go out with the next release that I'm aiming to cut by the end of the week.

@kalafut
Copy link
Contributor

kalafut commented Aug 6, 2019

Hi @lawliet89. I'm reviewing your PR and everything is looking good so far. One not-obvious thing about the relationship between roles and keys is that you can reference a non-existent named key when you make a role. Of course it will fail if used, but it won't fail at config time. So you should be able to:

  1. Make a role with the desired (but not yet existing) named key
  2. Save the client_id from the new role
  3. Make the named key, referencing the client_id

That might simplify some logic.

@lawliet89
Copy link
Contributor Author

lawliet89 commented Aug 6, 2019

@kalafut I see what you mean. But I think there is a use case for the vault_identity_oidc_key_allowed_client_id resource to allow more flexibility of adding of Client IDs to a named key, much like the AWS Security Group and Rules.

I will add another example and explanation to the documentation to make the two workflows clearer. (See ec58619)

if rs.Type != "vault_identity_oidc_key" {
continue
}
secret, err := client.Logical().Read(identityEntityIDPath(rs.Primary.ID))
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you instead want something like: resp, err := identityOidcKeyApiRead(rs.Primary.Attributes["name"], client) ?

Not that when looking at this I discovered that Vault is incorrectly returning a 400 for key not found instead of 404. I've just fixed that, but in the interim you may need the subsequent check to be something like:

if err != nil && !strings.Contains(err.Error(), "no named key found") {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've fixed this and added the check in identityOidcKeyApiRead(commit 34517b6).

@kalafut
Copy link
Contributor

kalafut commented Aug 7, 2019

@lawliet89 Yeah I can see that use, and actually I'd misinterpreted things the first time around and thought the vault_identity_oidc_key_allowed_client_id was required. So I'm OK with this.

@kalafut
Copy link
Contributor

kalafut commented Aug 7, 2019

@lawliet89 Key deletion will be blocked if there are roles referencing the key. For this provider I see a couple of issues:

  1. If you're trying to remove a key and there are referencing roles, the returned error isn't very helpful "Error: error IdentityOidcKey "mykey". The API response is: unable to delete key "mykey" because it is currently referenced by these roles: myrole
  2. If you're trying to remove both a key and associated roles, this will error the first time during the key delete step (there are still roles), but then it deletes the roles and an second terraform apply will work. The deletes should be ordered so roles are always removed before keys.

@kalafut
Copy link
Contributor

kalafut commented Aug 7, 2019

@lawliet89 By the way, I think this is good as-is if we hit our release/merge window, and the latest comments can be follow-on improvements if need be. Thanks!

@lawliet89
Copy link
Contributor Author

If you're trying to remove a key and there are referencing roles, the returned error isn't very helpful "Error: error IdentityOidcKey "mykey". The API response is: unable to delete key "mykey" because it is currently referenced by these roles: myrole

Fixed the error formatting for that.

If you're trying to remove both a key and associated roles, this will error the first time during the key delete step (there are still roles), but then it deletes the roles and an second terraform apply will work. The deletes should be ordered so roles are always removed before keys.

I don't think this can be done from the provider. Terraform will delete things in reverse dependency order. So the user will have to implicitly or explicitly have the role depend on the key for the destroy to work in one single operation.

@tyrannosaurus-becks
Copy link
Contributor

I'm going to go ahead and merge this because I see that the linked PR was taken off this branch, so its diff will be smaller when this is merged. Going to merge this then go take a look.

@tyrannosaurus-becks tyrannosaurus-becks merged commit 8a4b776 into hashicorp:master Aug 8, 2019
@lawliet89 lawliet89 deleted the vault-oidc branch August 9, 2019 00:26
@lawliet89 lawliet89 mentioned this pull request Nov 5, 2019
dandandy pushed a commit to dandandy/terraform-provider-vault that referenced this pull request Jun 17, 2021
Add resources for Vault Identity Tokens
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.

3 participants