├── .gitignore ├── Makefile ├── README.md ├── main.tf ├── outputs.tf ├── scripts └── docs.sh ├── variables.tf └── versions.tf /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | 11 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 12 | # .tfvars files are managed as part of configuration and so should be included in 13 | # version control. 14 | # 15 | terraform.tfvars 16 | 17 | # Ignore override files as they are usually used to override resources locally and so 18 | # are not checked in 19 | override.tf 20 | override.tf.json 21 | *_override.tf 22 | *_override.tf.json 23 | 24 | # Ignore CLI configuration files 25 | .terraformrc 26 | terraform.rc 27 | 28 | ca.crt 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | docs: 2 | ./scripts/docs.sh 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-vault-okta 2 | 3 | Terraform configuration to configure Vault with Okta using the OIDC auth plugin 4 | 5 | ## Usage 6 | 7 | ``` 8 | module "okta" { 9 | source = "onetwopunch/okta/vault" 10 | version = "" 11 | 12 | okta_discovery_url = "" 13 | okta_client_id = "" 14 | okta_client_secret = "" 15 | vault_addr = "https://:8200" 16 | okta_bound_audiences = [ 17 | "api://vault", 18 | "" 19 | ] 20 | 21 | roles = { 22 | okta_admin = { 23 | token_policies = ["admin"] 24 | bound_groups = ["vault_admins"] 25 | }, 26 | okta_devs = { 27 | token_policies = ["devs"] 28 | bound_groups = ["vault_devs"] 29 | } 30 | } 31 | } 32 | ``` 33 | 34 | ### Login via the CLI 35 | 36 | Login either via the UI or the CLI. If you want to get a local vault token, you'll need to run the following command, which will spin up a listener process by default on port 8250. You can override this with `port=xxx` in this command but you'll need to also update the redirect URIs in Okta and add the `cli_port` terraform variable. 37 | 38 | ``` 39 | vault login -method=oidc -path=okta_oidc role=okta-admin 40 | ``` 41 | 42 | ## Setting up Okta OIDC Auth 43 | 44 | For this to work, you'll need to be an Okta administrator: 45 | 46 | ### Setting up Groups 47 | 48 | Let's create two groups: `vault_admins` or something similar. These groups will be given permissions to do things within Vault. Within those groups, let's add some users in the Okta Admin console. 49 | 50 | ### Configuring the Authorization Server 51 | 52 | Okta has a default authorization server that you can either edit or create another one. You get to this setting by going to `Security > API > Authorization Servers`. For this, we'll create a new one. 53 | 54 | #### New Authorization Server for Vault 55 | 56 | Click `Add Authorization Server`. For name enter `Vault`, for audience enter `api://vault`, and then enter a meaningful description. 57 | 58 | #### Update Groups Claim 59 | 60 | Now click into the authz server you just created and go to the `Claims` tab. We need to add a `groups` claim so Vault knows what group this user belongs to. 61 | 62 | In the `Claims` tab, click on `Add Claim` with the following attributes: 63 | 64 | * Name: `groups` 65 | * Include in Token Type: `ID Token` `Always` 66 | * Value Type: Groups 67 | * Filter: `Starts with:` `vault_` 68 | * Include in: `The following scopes:` `profile` 69 | 70 | Click `Create` 71 | 72 | #### Access Policy 73 | 74 | This policy grants Vault access to read the necessary scopes to the authorization 75 | 76 | In the `Access Policy` tab, click `Add Policy` and give it the following attributes: 77 | 78 | * Name: `Vault Policy` 79 | * Description: `Default policy for Vault` 80 | * Assign to: `All clients` 81 | 82 | In that policy, we need to add a rule with the following attributes: 83 | 84 | * Rule Name: `default` 85 | * Grant Type: `Authorization Code` `Implicit` 86 | * User is: `Any user assigned the app` 87 | * Scopes requested: `Any Scopes` 88 | 89 | The rest of the config is dependent on your standards. 90 | 91 | #### Terraform Variables 92 | 93 | Take note of the following fields from this step, which we'll input into Terraform: 94 | 95 | * `Issuer URI` will be plugged in as `oidc_discovery_url` and `bound_issuer` in the OIDC path config 96 | * `Audience` will be plugged in as one of the `bound_audiences` in the role config 97 | 98 | ### Vault Okta Application 99 | 100 | We need to actually create a new web application for Vault to pop open the UI for Okta when requested. 101 | 102 | Under `Applications` click, `Add Application > Create New App` with the following attributes: 103 | 104 | * Platform: `Web` 105 | * Sign on method: `OpenID Connect` 106 | 107 | Then in the configuration: 108 | 109 | * Application Name: `Vault` 110 | * Application logo: ` 111 | * Login Redirect URIs: `https://:8200/ui/vault//oidc/callback` 112 | 113 | Note the `` denoted in the login URI is whatever value you are planning on using for the mount path for the OIDC plugin. In our case we used `okta_oidc` 114 | 115 | Click `Save` 116 | 117 | Now edit the general settings to ensure: 118 | 119 | * Allowed Grant Types: `Implicit (Hybrid)` `Allow ID Token with implicit grant type` 120 | * Login initiated by: `App Only` 121 | 122 | Click the `Sign On` tab and edit: 123 | 124 | * `OpenID Connect ID Token` to include the same `groups` claim we added in the authorization server with the filter `vault\_` 125 | 126 | Under `Assignments` add all the users or groups you want assigned to use Vault. 127 | 128 | Under `Okta API Scopes` you'll need to grant the application acess to the following: 129 | 130 | * `okta.groups.read` 131 | * `okta.users.read.self` 132 | 133 | #### Terraform Variables 134 | 135 | Take note of the following fields from this step, which we'll input into Terraform: 136 | 137 | * Login Redirect URI will be plugged into the role config as one of `allowed_redirect_uris` 138 | * Client ID and Client Secret will be plugged into the path config as `oidc_client_id` and `oidc_client_secret` respectively 139 | * Under `Sign On > OpenID Connect ID Token` the `Audience` field which looks like `0oa...` is passed in as a second value in the `bound_audiences` list in the role config. 140 | * The groups you created that are prefixed by `vault\_` can be passed in as the `allowed_groups` variable in the role config. 141 | 142 | ## Deploy 143 | 144 | First export the following variables to point at your Vault cluster 145 | 146 | ``` 147 | export VAULT_ADDR=https://:8200 148 | export VAULT_CACERT= 149 | ``` 150 | 151 | Then we use terraform to apply the changes: 152 | 153 | ``` 154 | terraform apply 155 | ``` 156 | 157 | 158 | ## Providers 159 | 160 | | Name | Version | 161 | |------|---------| 162 | | vault | ~> 2.11 | 163 | 164 | ## Inputs 165 | 166 | | Name | Description | Type | Default | Required | 167 | |------|-------------|------|---------|:-----:| 168 | | okta\_bound\_audiences | A list of allowed token audiences | `list` | n/a | yes | 169 | | okta\_client\_id | Okta Vault app client ID | `string` | n/a | yes | 170 | | okta\_client\_secret | Okta Vault app client secret | `string` | n/a | yes | 171 | | okta\_discovery\_url | Okta Authz server Issuer URI: i.e. https://.okta.com/oauth2/ | `string` | n/a | yes | 172 | | vault\_addr | Vault address in the form of https://domain:8200 | `string` | n/a | yes | 173 | | cli\_port | Port to open locally to login with the CLI | `number` | `8250` | no | 174 | | okta\_allowed\_groups | Okta group for Vault admins | `list` |
[
"vault_admins"
]
| no | 175 | | okta\_mount\_path | Mount path for Okta auth | `string` | `"okta_oidc"` | no | 176 | | roles | Map of Vault role names to their bound groups and token policies. Structure looks like this:
roles = {
okta_admin = {
token_policies = ["admin"]
bound_groups = ["vault_admins"]
},
okta_devs = {
token_policies = ["devs"]
bound_groups = ["vault_devs"]
}
}
| `map` | `{}` | no | 177 | | okta\_default\_lease\_ttl | Default lease TTL for Vault tokens | `string` | `"768h"` | no | 178 | | okta\_max\_lease\_ttl | Maximum lease TTL for Vault tokens | `string` | `"768h"` | no | 179 | | okta\_token\_type | Token type for Vault tokens | `string` | `"default-service"` | no | 180 | 181 | ## Outputs 182 | 183 | | Name | Description | 184 | |------|-------------| 185 | | path | Okta OIDC auth path | 186 | | roles | Role names created by this module | 187 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | resource "vault_jwt_auth_backend" "okta_oidc" { 18 | description = "Okta OIDC" 19 | path = var.okta_mount_path 20 | type = "oidc" 21 | oidc_discovery_url = var.okta_discovery_url 22 | bound_issuer = var.okta_discovery_url 23 | oidc_client_id = var.okta_client_id 24 | oidc_client_secret = var.okta_client_secret 25 | tune { 26 | listing_visibility = "unauth" 27 | default_lease_ttl = var.okta_default_lease_ttl 28 | max_lease_ttl = var.okta_max_lease_ttl 29 | token_type = var.okta_token_type 30 | } 31 | } 32 | 33 | resource "vault_jwt_auth_backend_role" "okta_role" { 34 | for_each = var.roles 35 | backend = vault_jwt_auth_backend.okta_oidc.path 36 | role_name = each.key 37 | token_policies = each.value.token_policies 38 | 39 | allowed_redirect_uris = [ 40 | "${var.vault_addr}/ui/vault/auth/${vault_jwt_auth_backend.okta_oidc.path}/oidc/callback", 41 | 42 | # This is for logging in with the CLI if you want. 43 | "http://localhost:${var.cli_port}/oidc/callback", 44 | ] 45 | 46 | user_claim = "email" 47 | role_type = "oidc" 48 | bound_audiences = var.okta_bound_audiences 49 | oidc_scopes = [ 50 | "openid", 51 | "profile", 52 | "email", 53 | ] 54 | bound_claims = { 55 | groups = join(",", each.value.bound_groups) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "roles" { 18 | description = "Role names created by this module" 19 | value = keys(vault_jwt_auth_backend_role.okta_role) 20 | } 21 | 22 | output "path" { 23 | description = "Okta OIDC auth path" 24 | value = vault_jwt_auth_backend.okta_oidc.path 25 | } 26 | -------------------------------------------------------------------------------- /scripts/docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Removes old docs from the end of the README and generates new ones 4 | 5 | doc_start=$(grep -n '' README.md | cut -f1 -d':') 6 | head -$doc_start README.md > README.md.bak 7 | terraform-docs md table --sort-by-required . >> README.md.bak 8 | mv README.md.bak README.md 9 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "vault_addr" { 18 | type = string 19 | description = "Vault address in the form of https://domain:8200" 20 | } 21 | 22 | variable "okta_discovery_url" { 23 | type = string 24 | description = "Okta Authz server Issuer URI: i.e. https://.okta.com/oauth2/" 25 | } 26 | 27 | variable "okta_allowed_groups" { 28 | type = list 29 | description = "Okta group for Vault admins" 30 | default = ["vault_admins"] 31 | } 32 | 33 | variable "okta_mount_path" { 34 | type = string 35 | description = "Mount path for Okta auth" 36 | default = "okta_oidc" 37 | } 38 | 39 | variable "okta_client_id" { 40 | type = string 41 | description = "Okta Vault app client ID" 42 | } 43 | 44 | variable "okta_client_secret" { 45 | type = string 46 | description = "Okta Vault app client secret" 47 | } 48 | 49 | variable "okta_bound_audiences" { 50 | type = list 51 | description = "A list of allowed token audiences" 52 | } 53 | 54 | variable "cli_port" { 55 | type = number 56 | description = "Port to open locally to login with the CLI" 57 | default = 8250 58 | } 59 | 60 | variable "okta_default_lease_ttl" { 61 | type = string 62 | description = "Default lease TTL for Vault tokens" 63 | default = "768h" 64 | } 65 | 66 | variable "okta_max_lease_ttl" { 67 | type = string 68 | description = "Maximum lease TTL for Vault tokens" 69 | default = "768h" 70 | } 71 | 72 | variable "okta_token_type" { 73 | type = string 74 | description = "Token type for Vault tokens" 75 | default = "default-service" 76 | } 77 | 78 | variable "roles" { 79 | type = map 80 | default = {} 81 | 82 | description = <