Skip to content

Instantly share code, notes, and snippets.

@memes
Last active February 15, 2023 12:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save memes/3267553b31ba0f662b8fb601560c53b7 to your computer and use it in GitHub Desktop.
Save memes/3267553b31ba0f662b8fb601560c53b7 to your computer and use it in GitHub Desktop.
Vault OIDC configuration workaround for hashicorp/terraform-provider-vault#957
resource "vault_policy" "admin" {
name = "admin"
policy = <<EOP
# Manage auth methods broadly across Vault
path "auth/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Create, update, and delete auth methods
path "sys/auth/*"
{
capabilities = ["create", "update", "delete", "sudo"]
}
# List auth methods
path "sys/auth"
{
capabilities = ["read"]
}
# List existing policies
path "sys/policies/acl"
{
capabilities = ["list"]
}
# Create and manage ACL policies
path "sys/policies/acl/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage secrets engines
path "sys/mounts/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List existing secrets engines.
path "sys/mounts"
{
capabilities = ["read"]
}
# Read health checks
path "sys/health"
{
capabilities = ["read", "sudo"]
}
# List, create, update, and delete KV secrets.
path "secret/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List, create, update, and delete PKI engine.
path "pki/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List, create, update, and delete PKI CA engine.
path "pki_ca/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOP
}
# Configures GSuite as an OIDC/JWT provider and maps groups to Vault
# aliases to elevate privileges as needed.
resource "vault_jwt_auth_backend" "oidc" {
type = "oidc"
path = "oidc"
oidc_discovery_url = "https://accounts.google.com"
oidc_client_id = var.gsuite_client_id
oidc_client_secret = var.gsuite_client_secret
default_role = "domain_user"
provider_config = {
provider = "gsuite"
gsuite_service_account = var.gsuite_service_account_cred_path
gsuite_admin_impersonate = var.gsuite_admin_impersonate_account
# Manually update this from command line to make sure it is setting all
# params correctly and ignore changes until fixed.
# https://github.com/hashicorp/terraform-provider-vault/issues/957
# fetch_groups = true
# fetch_user_info = false
# groups_recurse_max_depth = 5
user_custom_schemas = ""
}
lifecycle {
ignore_changes = [
provider_config,
]
}
}
resource "vault_jwt_auth_backend_role" "domain_user" {
backend = vault_jwt_auth_backend.oidc.path
role_name = "domain_user"
role_type = vault_jwt_auth_backend.oidc.type
allowed_redirect_uris = [
"https://vault.lab.acceleratedgcp.com:8200/ui/vault/auth/oidc/oidc/callback",
"http://localhost:8250/oidc/callback",
]
user_claim = "sub"
groups_claim = "groups"
# Domain users get default policy always
token_policies = ["default"]
}
# Link the Vault admin policy to the domain admin group
resource "vault_identity_group" "admins" {
name = var.gsuite_admin_group
type = "external"
policies = [
vault_policy.admin.name,
]
metadata = {
responsibility = "Admin Group"
}
}
resource "vault_identity_group_alias" "admins_alias" {
name = var.gsuite_admin_group
mount_accessor = vault_jwt_auth_backend.oidc.accessor
canonical_id = vault_identity_group.admins.id
}
# Write the configuration file that needs to be imported by `vault write -tls-skip-verify auth/oidc/config @oidc.json`
resource "local_file" "oidc_json" {
filename = "oidc.json"
content = jsonencode({
oidc_discovery_url = "https://accounts.google.com"
oidc_client_id = var.gsuite_client_id
oidc_client_secret = var.gsuite_client_secret
default_role = "domain_user"
provider_config = {
provider = "gsuite"
gsuite_service_account = var.gsuite_service_account_cred_path
gsuite_admin_impersonate = var.gsuite_admin_impersonate_account
fetch_groups = true
fetch_user_info = false
groups_recurse_max_depth = 5
user_custom_schemas = ""
}
})
}
# From the OIDC credentials screen: client id and secret
gsuite_client_id = "NNNNNNNNNNNN-xxxxxxxxxxx.apps.googleusercontent.com"
gsuite_client_secret = "XxXxXxXxXxX"
# Path to service account JSON on vault server
gsuite_service_account_cred_path = "/var/lib/vault/vault-sa.json"
# The GSuite *SUPER USER* account that can perform lookups
gsuite_admin_impersonate_account = "admin@example.com"
# The GSuite *GROUP* that will be granted admin policy
gsuite_admin_group = "lab-admins@example.com"
variable "gsuite_client_id" {
type = string
}
variable "gsuite_client_secret" {
type = string
}
variable "gsuite_service_account_cred_path" {
type = string
}
variable "gsuite_admin_impersonate_account" {
type = string
}
variable "gsuite_admin_group" {
type = string
}
@memes
Copy link
Author

memes commented Apr 28, 2021

Snippet of the Terraform I use to setup Vault OIDC with GSuite

  • OIDC authentication has path /auth/oidc
  • Allowed redirects are on lines 36-37; change line 36 to match the FQDN for your Vault server, add more entries if needed
  • All domain users can authenticate via GSuite and will be given whatever is the default policy in your vault (oidc.tf L42). This allows me to setup aliases for non-admin users, etc.
  • Members of the admin group (e.g. gsuite_admin_group = lab-admins@example.com will be granted the policies referred to in (oidc.tf L49-51). For me this is an admin policy defined in the main.tf (censored snippet shown here)
  • A local file oidc.json will be created on terraform apply which can be imported into Vault to complete the configuration

Steps

  1. Edit terraform.tfvars to match your GSuite and OIDC credentials

  2. Edit oidc.tf to assign the correct policy to admins, or any other group you need

  3. Login to Vault as root (or equivalent)

  4. Apply and post the oidc.json to Vault

    terraform init
    terraform apply [-auto-approve]

    Make sure the generated oidc.json looks good and POST to Vault

    vault write -tls-skip-verify auth/oidc/config @oidc.json
  5. You should now be able to revoke the root token and use method oidc to login

    vault token revoke s.ROOT_TOKEN
    vault login -method=oidc
    Complete the login via your OIDC provider. Launching browser to:
    
    https://accounts.google.com/o/oauth2/v2/auth?client_id=XXXXXXXXXXXXXXXXX
    
    Success! You are now authenticated. The token information displayed below
    is already stored in the token helper. You do NOT need to run "vault login"
    again. Future Vault requests will automatically use this token.
    
    Key                  Value
    ---                  -----
    token                s.XXXXXX
    token_accessor       XXXXX
    token_duration       XXh
    token_renewable      true
    token_policies       ["default"]
    identity_policies    ["admin"]
    policies             ["admin" "default"]
    token_meta_role      domain_user
    

@souzaxx
Copy link

souzaxx commented Jul 4, 2022

Thanks for this tutorial! Worked super fine!

@teochenglim
Copy link

Could you kindly explain "local_file. oidc_json" and "vault_jwt_auth_backend.oidc", it seems duplicated to me.

@memes
Copy link
Author

memes commented Dec 7, 2022

@teochenglim - this gist outlines a way to work around an historical bug in the Vault provider that was fixed in 2021. If you are using a recent version of the Vault provider you do not need this workaround - e.g. https://github.com/memes/lab-config/blob/main/vault/oidc.tf#L11-L19 shows that the properties can be set correctly from within the provider.

Explanation of gist approach

Bug 957 prevented setting the OIDC properties correctly; if you look at lines 11-22 in oidc.tf you can see that some required properties are commented out because of the bug. Since OIDC against GSuite will fail without those properties, it was necessary to manually apply a JSON file to Vault to fix the missing properties. Essentially configuring OIDC for GSuite through Vault was a two-step process:

  1. Create the resource
  2. Apply JSON to fix missing properties

The example Terraform in this gist creates the Vault OIDC resource with a partial configuration and generates the JSON file that can complete the configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment