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 OIDC Provider support to TFVP #1363

Merged
merged 32 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
410ea17
initial commit for OIDC Scope resource
vinay-gopalan Feb 22, 2022
1027430
update func names
vinay-gopalan Feb 25, 2022
04b49df
add OIDC Assignment resource
vinay-gopalan Feb 25, 2022
9dd295b
add documentation for OIDC scopes and assignments
vinay-gopalan Feb 25, 2022
6fe675a
revert statefunc
vinay-gopalan Mar 1, 2022
f83ff02
Merge Client and Provider resources to OIDC feature branch (#1368)
vinay-gopalan Mar 5, 2022
7cbce79
add docs for OIDC Client and Provider resources
vinay-gopalan Mar 14, 2022
002b0ae
convert lists to sets, test name field for resources
vinay-gopalan Mar 14, 2022
c3b982e
add client_id and client_secret to OIDC Client resource
vinay-gopalan Mar 14, 2022
ab25408
remove datasource from provider tests and examples
vinay-gopalan Mar 15, 2022
4848385
add data source for OIDC Public keys
vinay-gopalan Mar 17, 2022
84e5055
add datasource for openID configuration endpoint
vinay-gopalan Mar 17, 2022
d48eaac
fix scopes in provider test
vinay-gopalan Mar 17, 2022
a440827
rename file
vinay-gopalan Mar 17, 2022
9d0d2c2
make secrets sensitive fields
vinay-gopalan Mar 17, 2022
e0505e7
fix breaking test for OIDC public keys
vinay-gopalan Mar 18, 2022
1e9f8a3
update docs and data sources with feedback
vinay-gopalan Mar 21, 2022
30da4de
add openID schema to config data source
vinay-gopalan Mar 21, 2022
2b611a8
add test for openID Config datasource
vinay-gopalan Mar 21, 2022
9069211
add documentation for public endpoint data sources
vinay-gopalan Mar 21, 2022
eeb66cf
add test for client creds data source
vinay-gopalan Mar 21, 2022
540d559
add initial fixes for breaking tests
vinay-gopalan Mar 22, 2022
a11db92
add new fields issuer_host and https_enabled in order to fix issuer d…
vinay-gopalan Mar 23, 2022
385cb47
randomize resource names in tests
vinay-gopalan Mar 23, 2022
8678e12
set issuer only if host is non-empty
vinay-gopalan Mar 23, 2022
c8b5907
remove skip flag from client test
vinay-gopalan Mar 24, 2022
62e9af7
Merge branch 'release/vault-next' into resource/oidc-scope-assignments
vinay-gopalan Mar 24, 2022
68a0eb6
remove unnecessary diff and validate funcs
vinay-gopalan Mar 24, 2022
e54f0f3
update provider resource docs
vinay-gopalan Mar 24, 2022
10995f4
docs fixes; typo in key names
vinay-gopalan Mar 24, 2022
09b8e73
remove forcenew behavior from issuer field
vinay-gopalan Mar 24, 2022
72c5306
add datasource docs to vault.erb sidebar
vinay-gopalan Mar 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions vault/data_identity_oidc_client_creds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package vault

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"
)

func identityOIDCClientCredsDataSource() *schema.Resource {
return &schema.Resource{
Read: readOIDCClientCredsResource,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the client.",
},
"client_id": {
Type: schema.TypeString,
Description: "The Client ID from Vault.",
Computed: true,
},
"client_secret": {
Type: schema.TypeString,
Description: "The Client Secret from Vault.",
Computed: true,
austingebauer marked this conversation as resolved.
Show resolved Hide resolved
Sensitive: true,
},
},
}
}

func readOIDCClientCredsResource(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
name := d.Get("name").(string)
path := getOIDCClientPath(name)

creds, err := client.Logical().Read(path)
if err != nil {
return fmt.Errorf("error reading from Vault, err=%w", err)
}

log.Printf("[DEBUG] Read %q from Vault", path)
benashz marked this conversation as resolved.
Show resolved Hide resolved

if creds == nil {
return fmt.Errorf("no client found at %q", path)
}

clientId := creds.Data["client_id"].(string)

if clientId == "" {
return fmt.Errorf("client_id is not set in response")
}

clientSecret := creds.Data["client_secret"].(string)
if clientSecret == "" {
return fmt.Errorf("client_secret is not set in response")
}

d.SetId(path)

if err := d.Set("client_id", clientId); err != nil {
return err
}

if err := d.Set("client_secret", clientSecret); err != nil {
return err
}

return nil
}
54 changes: 54 additions & 0 deletions vault/data_identity_oidc_client_creds_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package vault

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/hashicorp/terraform-provider-vault/testutil"
)

func TestDataSourceIdentityOIDCClientCreds(t *testing.T) {
name := acctest.RandomWithPrefix("test-client")

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceIdentityOIDCClientCreds_config(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.vault_identity_oidc_client_creds.creds", "name", name),
),
},
},
})
}

func testDataSourceIdentityOIDCClientCreds_config(name string) string {
return fmt.Sprintf(`
resource "vault_identity_oidc_key" "key" {
name = "key"
allowed_client_ids = ["*"]
rotation_period = 3600
verification_ttl = 3600
}

resource "vault_identity_oidc_client" "test" {
name = "%s"
key = vault_identity_oidc_key.key.name
redirect_uris = [
"http://127.0.0.1:9200/v1/auth-methods/oidc:authenticate:callback",
"http://127.0.0.1:8251/callback",
"http://127.0.0.1:8080/callback"
]
id_token_ttl = 2400
access_token_ttl = 7200
}

data "vault_identity_oidc_client_creds" "creds" {
name = vault_identity_oidc_client.test.name
}`, name)
}
151 changes: 151 additions & 0 deletions vault/data_identity_oidc_openid_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package vault
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved

import (
"encoding/json"
"fmt"
"io"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"
)

const identityOIDCOpenIDConfigPathSuffix = "/.well-known/openid-configuration"

func identityOIDCOpenIDConfigDataSource() *schema.Resource {
return &schema.Resource{
Read: readOIDCOpenIDConfigResource,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the provider.",
},
"issuer": {
Type: schema.TypeString,
Computed: true,
Description: "The URL of the issuer for the provider.",
},
"jwks_uri": {
Type: schema.TypeString,
Computed: true,
Description: "The well known keys URI for the provider.",
},
"authorization_endpoint": {
Type: schema.TypeString,
Computed: true,
Description: "The Authorization Endpoint for the provider.",
},
"token_endpoint": {
Type: schema.TypeString,
Computed: true,
Description: "The Token Endpoint for the provider.",
},
"userinfo_endpoint": {
Type: schema.TypeString,
Computed: true,
Description: "The User Info Endpoint for the provider.",
},
"request_uri_parameter_supported": {
Type: schema.TypeBool,
Computed: true,
Description: "Specifies whether Request URI Parameter is supported by the provider.",
},
"id_token_signing_alg_values_supported": {
Type: schema.TypeList,
Computed: true,
Description: "The signing algorithms supported by the provider.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"response_types_supported": {
Type: schema.TypeList,
Computed: true,
Description: "The response types supported by the provider.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"scopes_supported": {
Type: schema.TypeList,
Computed: true,
Description: "The scopes supported by the provider.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"subject_types_supported": {
Type: schema.TypeList,
Computed: true,
Description: "The subject types supported by the provider.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"grant_types_supported": {
Type: schema.TypeList,
Computed: true,
Description: "The grant types supported by the provider.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"token_endpoint_auth_methods_supported": {
Type: schema.TypeList,
Computed: true,
Description: "The token endpoint auth methods supported by the provider.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func readOIDCOpenIDConfigResource(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
name := d.Get("name").(string)
path := "/v1/" + getOIDCProviderPath(name) + identityOIDCOpenIDConfigPathSuffix
r := client.NewRequest("GET", path)

log.Printf("[DEBUG] Reading %q from Vault", path)
resp, err := client.RawRequest(r)
if err != nil {
return fmt.Errorf("error performing GET at %s, err=%w", path, err)
}

if resp == nil {
return fmt.Errorf("expected a response body, got nil response")
}

benashz marked this conversation as resolved.
Show resolved Hide resolved
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

var data map[string]interface{}
if err := json.Unmarshal(body, &data); err != nil {
return err
}

d.SetId(path)

openIDConfigFields := []string{
"issuer", "jwks_uri", "authorization_endpoint", "token_endpoint",
"userinfo_endpoint", "request_uri_parameter_supported",
"id_token_signing_alg_values_supported", "response_types_supported",
"scopes_supported", "subject_types_supported", "grant_types_supported",
"token_endpoint_auth_methods_supported",
}

for _, k := range openIDConfigFields {
if err := d.Set(k, data[k]); err != nil {
return fmt.Errorf("error setting state key %q on OpenID Config %q, err=%w", k, path, err)
}
}

return nil
}
94 changes: 94 additions & 0 deletions vault/data_identity_oidc_openid_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package vault

import (
"fmt"
"net/url"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/hashicorp/terraform-provider-vault/testutil"
)

func TestDataSourceIdentityOIDCOpenIDConfig(t *testing.T) {
providerName := acctest.RandomWithPrefix("test-provider")
keyName := acctest.RandomWithPrefix("test-key")
clientName := acctest.RandomWithPrefix("test-client")

resourceName := "data.vault_identity_oidc_openid_config.config"
vaultAddrEnv := os.Getenv("VAULT_ADDR")
parsedUrl, err := url.Parse(vaultAddrEnv)
if err != nil {
t.Fatal(err)
}

host := parsedUrl.Host
if host == "localhost:8200" {
host = "127.0.0.1:8200"
}

issuer := "http://%s/v1/identity/oidc/provider/%s"
jwksURI := "http://%s/v1/identity/oidc/provider/%s/.well-known/keys"
authorizationEndpoint := "http://%s/ui/vault/identity/oidc/provider/%s/authorize"
tokenEndpoint := "http://%s/v1/identity/oidc/provider/%s/token"
userInfoEndpoint := "http://%s/v1/identity/oidc/provider/%s/userinfo"

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceIdentityOIDCOpenIDConfig_config(keyName, clientName, providerName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", providerName),
resource.TestCheckResourceAttr(resourceName, "issuer", fmt.Sprintf(issuer, host, providerName)),
resource.TestCheckResourceAttr(resourceName, "jwks_uri", fmt.Sprintf(jwksURI, host, providerName)),
resource.TestCheckResourceAttr(resourceName, "authorization_endpoint", fmt.Sprintf(authorizationEndpoint, host, providerName)),
resource.TestCheckResourceAttr(resourceName, "token_endpoint", fmt.Sprintf(tokenEndpoint, host, providerName)),
resource.TestCheckResourceAttr(resourceName, "userinfo_endpoint", fmt.Sprintf(userInfoEndpoint, host, providerName)),
resource.TestCheckResourceAttr(resourceName, "request_uri_parameter_supported", "false"),
resource.TestCheckResourceAttr(resourceName, "id_token_signing_alg_values_supported.#", "7"),
resource.TestCheckResourceAttr(resourceName, "scopes_supported.#", "1"),
resource.TestCheckResourceAttr(resourceName, "scopes_supported.0", "openid"),
),
},
},
})
}

func testDataSourceIdentityOIDCOpenIDConfig_config(keyName, clientName, providerName string) string {
return fmt.Sprintf(`
resource "vault_identity_oidc_key" "key" {
name = "%s"
allowed_client_ids = ["*"]
rotation_period = 3600
verification_ttl = 3600
}

resource "vault_identity_oidc_client" "app" {
name = "%s"
key = vault_identity_oidc_key.key.name
redirect_uris = [
"http://127.0.0.1:9200/v1/auth-methods/oidc:authenticate:callback",
"http://127.0.0.1:8251/callback",
"http://127.0.0.1:8080/callback"
]
id_token_ttl = 2400
access_token_ttl = 7200
}

resource "vault_identity_oidc_provider" "test" {
name = "%s"
https_enabled = false
issuer_host = "127.0.0.1:8200"
allowed_client_ids = [
vault_identity_oidc_client.app.client_id
]
}

data "vault_identity_oidc_openid_config" "config" {
name = vault_identity_oidc_provider.test.name
}`, keyName, clientName, providerName)
}
Loading