Skip to content

Commit

Permalink
Merge pull request hashicorp#398 from sergeytrasko/oidc
Browse files Browse the repository at this point in the history
Support OIDC auth backends
  • Loading branch information
tyrannosaurus-becks authored May 7, 2019
2 parents 98fb073 + 78da219 commit 3654e6e
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 14 deletions.
2 changes: 1 addition & 1 deletion vault/resource_auth_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func authBackendResource() *schema.Resource {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Description: "Speficies whether to show this mount in the UI-specific listing endpoint",
Description: "Specifies whether to show this mount in the UI-specific listing endpoint",
},

"local": {
Expand Down
71 changes: 63 additions & 8 deletions vault/resource_jwt_auth_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import (
"log"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/hashicorp/vault/api"
)

var jwtAuthType = "jwt"

func jwtAuthBackendResource() *schema.Resource {
return &schema.Resource{
Create: jwtAuthBackendWrite,
Expand All @@ -25,10 +24,19 @@ func jwtAuthBackendResource() *schema.Resource {
Optional: true,
ForceNew: true,
Description: "path to mount the backend",
Default: jwtAuthType,
Default: "jwt",
ValidateFunc: validateNoTrailingSlash,
},

"type": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "Type of backend. Can be either 'jwt' or 'oidc'",
Default: "jwt",
ValidateFunc: validation.StringInSlice([]string{"jwt", "oidc"}, false),
},

"description": {
Type: schema.TypeString,
Required: false,
Expand All @@ -43,6 +51,19 @@ func jwtAuthBackendResource() *schema.Resource {
Description: "The OIDC Discovery URL, without any .well-known component (base path)",
},

"oidc_client_id": {
Type: schema.TypeString,
Optional: true,
Description: "Client ID used for OIDC",
},

"oidc_client_secret": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Description: "Client Secret used for OIDC",
},

"oidc_discovery_ca_pem": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -69,19 +90,26 @@ func jwtAuthBackendResource() *schema.Resource {
Description: "A list of supported signing algorithms. Defaults to [RS256]",
},

"default_role": {
Type: schema.TypeString,
Optional: true,
Description: "The default role to use if none is provided during login",
},

"accessor": {
Type: schema.TypeString,
Computed: true,
Description: "The accessor of the JWT auth backend",
},
"tune": authMountTuneSchema(),
},
}
}

func jwtAuthBackendWrite(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

authType := jwtAuthType
authType := d.Get("type").(string)
desc := d.Get("description").(string)
path := getJwtPath(d)

Expand Down Expand Up @@ -146,7 +174,10 @@ func jwtAuthBackendRead(d *schema.ResourceData, meta interface{}) error {

d.Set("accessor", backend.Accessor)
d.Set("oidc_discovery_ca_pem", config.Data["oidc_discovery_ca_pem"])
d.Set("oidc_client_id", config.Data["oidc_client_id"])
d.Set("oidc_client_secret", config.Data["oidc_client_secret"])
d.Set("bound_issuer", config.Data["bound_issuer"])
d.Set("default_role", config.Data["default_role"])
d.Set("oidc_discovery_url", config.Data["oidc_discovery_url"])
d.Set("jwt_validation_pubkeys", config.Data["jwt_validation_pubkeys"])
d.Set("jwt_supported_algs", config.Data["jwt_supported_algs"])
Expand All @@ -168,7 +199,6 @@ func jwtAuthBackendUpdate(d *schema.ResourceData, meta interface{}) error {

oidcDiscoveryUrl, oidcDiscoveryUrlExists := d.GetOk("oidc_discovery_url")
jwtValidationPubKeys, jwtValidationPubKeysExists := d.GetOk("jwt_validation_pubkeys")
jwtSupportedAlgs, jwtSupportedAlgsExists := d.GetOk("jwt_supported_algs")

if oidcDiscoveryUrlExists == jwtValidationPubKeysExists {
return errors.New("exactly one of oidc_discovery_url and jwt_validation_pubkeys should be provided")
Expand All @@ -182,15 +212,40 @@ func jwtAuthBackendUpdate(d *schema.ResourceData, meta interface{}) error {
configuration["jwt_validation_pubkeys"] = jwtValidationPubKeys
}

if jwtSupportedAlgsExists {
configuration["jwt_supported_algs"] = jwtSupportedAlgs
if v, ok := d.GetOkExists("jwt_supported_algs"); ok {
configuration["jwt_supported_algs"] = v
}
if v, ok := d.GetOkExists("oidc_client_id"); ok {
configuration["oidc_client_id"] = v.(string)
}
if v, ok := d.GetOkExists("oidc_client_secret"); ok {
configuration["oidc_client_secret"] = v.(string)
}
if v, ok := d.GetOkExists("default_role"); ok {
configuration["default_role"] = v.(string)
}

_, err := client.Logical().Write(jwtConfigEndpoint(path), configuration)
if err != nil {
return fmt.Errorf("error updating configuration to Vault for path %s: %s", path, err)
}

if d.HasChange("tune") {
log.Printf("[INFO] JWT/OIDC Auth '%q' tune configuration changed", d.Id())
if raw, ok := d.GetOk("tune"); ok {
backendType := d.Get("type")
log.Printf("[DEBUG] Writing %s auth tune to '%q'", backendType, path)

err := authMountTune(client, "auth/"+path, raw)
if err != nil {
return nil
}

log.Printf("[INFO] Written %s auth tune to '%q'", backendType, path)
d.SetPartial("tune")
}
}

return jwtAuthBackendRead(d, meta)
}

Expand All @@ -208,7 +263,7 @@ func getJwtAuthBackendIfPresent(client *api.Client, path string) (*api.AuthMount

for authBackendPath, auth := range auths {

if auth.Type == jwtAuthType && authBackendPath == configuredPath {
if authBackendPath == configuredPath {
return auth, nil
}
}
Expand Down
66 changes: 66 additions & 0 deletions vault/resource_jwt_auth_backend_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ func jwtAuthBackendRoleResource() *schema.Resource {
},
Description: "Policies to be set on tokens issued using this role.",
},
"allowed_redirect_uris": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Description: "The list of allowed values for redirect_uri during OIDC logins.",
},
"ttl": {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -98,6 +106,24 @@ func jwtAuthBackendRoleResource() *schema.Resource {
Type: schema.TypeString,
},
},
"oidc_scopes": {
Type: schema.TypeSet,
Optional: true,
Description: "List of OIDC scopes to be used with an OIDC role. The standard scope \"openid\" is automatically included and need not be specified.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"bound_claims": {
Type: schema.TypeMap,
Optional: true,
Description: "Map of claims/values to match against. The expected value may be a single string or a list of strings.",
},
"claim_mappings": {
Type: schema.TypeMap,
Optional: true,
Description: "Map of claims (keys) to be copied to specified metadata fields (values).",
},
"groups_claim": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -196,6 +222,13 @@ func jwtAuthBackendRoleRead(d *schema.ResourceData, meta interface{}) error {
if err != nil {
return fmt.Errorf("error setting policies in state: %s", err)
}
if resp.Data["allowed_redirect_uris"] != nil {
allowedRedirectUris := util.JsonStringArrayToStringArray(resp.Data["allowed_redirect_uris"].([]interface{}))
err = d.Set("allowed_redirect_uris", allowedRedirectUris)
if err != nil {
return fmt.Errorf("error setting allowed_redirect_uris in state: %s", err)
}
}

tokenTTL, err := resp.Data["ttl"].(json.Number).Int64()
if err != nil {
Expand Down Expand Up @@ -234,6 +267,24 @@ func jwtAuthBackendRoleRead(d *schema.ResourceData, meta interface{}) error {
d.Set("bound_cidrs", make([]string, 0))
}

if resp.Data["oidc_scopes"] != nil {
cidrs := util.JsonStringArrayToStringArray(resp.Data["oidc_scopes"].([]interface{}))
err = d.Set("oidc_scopes", cidrs)
if err != nil {
return fmt.Errorf("error setting oidc_scopes in state: %s", err)
}
} else {
d.Set("oidc_scopes", make([]string, 0))
}

if resp.Data["bound_claims"] != nil {
d.Set("bound_claims", resp.Data["bound_claims"])
}

if resp.Data["claim_mappings"] != nil {
d.Set("claim_mappings", resp.Data["claim_mappings"])
}

d.Set("groups_claim", resp.Data["groups_claim"].(string))
if resp.Data["groups_claim_delimiter_pattern"] != nil {
d.Set("groups_claim_delimiter_pattern", resp.Data["groups_claim_delimiter_pattern"].(string))
Expand Down Expand Up @@ -343,6 +394,9 @@ func jwtAuthBackendRoleDataToWrite(d *schema.ResourceData) map[string]interface{
if dataList := util.TerraformSetToStringArray(d.Get("policies")); len(dataList) > 0 {
data["policies"] = dataList
}
if dataList := util.TerraformSetToStringArray(d.Get("allowed_redirect_uris")); len(dataList) > 0 {
data["allowed_redirect_uris"] = dataList
}

if v, ok := d.GetOk("role_type"); ok {
data["role_type"] = v.(string)
Expand All @@ -368,6 +422,18 @@ func jwtAuthBackendRoleDataToWrite(d *schema.ResourceData) map[string]interface{
data["bound_cidrs"] = dataList
}

if dataList := util.TerraformSetToStringArray(d.Get("oidc_scopes")); len(dataList) > 0 {
data["oidc_scopes"] = dataList
}

if v, ok := d.GetOk("bound_claims"); ok {
data["bound_claims"] = v
}

if v, ok := d.GetOk("claim_mappings"); ok {
data["claim_mappings"] = v
}

if v, ok := d.GetOkExists("groups_claim"); ok {
data["groups_claim"] = v.(string)
}
Expand Down
Loading

0 comments on commit 3654e6e

Please sign in to comment.