Skip to content

Commit

Permalink
[NET-5336] Support for templated policies
Browse files Browse the repository at this point in the history
  • Loading branch information
roncodingenthusiast committed Oct 13, 2023
1 parent ba52b81 commit c0a99e6
Show file tree
Hide file tree
Showing 8 changed files with 345 additions and 16 deletions.
40 changes: 39 additions & 1 deletion consul/resource_consul_acl_binding_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func resourceConsulACLBindingRule() *schema.Resource {
"bind_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Specifies the way the binding rule affects a token created at login.",
},

Expand All @@ -49,6 +50,23 @@ func resourceConsulACLBindingRule() *schema.Resource {
Description: "The name to bind to a token at login-time.",
},

"bind_vars": {
Type: schema.TypeList,
MaxItems: 1,
Computed: true,
Description: "BindVars is a the variables used when binding rule type is `templated-policy`. Can be lightly templated using HIL ${foo} syntax from available field names.",
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
Description: "The name of node, workload identity or service.",
},
},
},
},

"namespace": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -102,6 +120,13 @@ func resourceConsulACLBindingRuleRead(d *schema.ResourceData, meta interface{})
sw.set("namespace", rule.Namespace)
sw.set("partition", rule.Partition)

if rule.BindVars != nil {
bindVars := []map[string]interface{}{
{"name": rule.BindVars.Name},
}
sw.set("bind_vars", bindVars)
}

return sw.error()
}

Expand Down Expand Up @@ -134,7 +159,7 @@ func resourceConsulACLBindingRuleDelete(d *schema.ResourceData, meta interface{}

func getBindingRule(d *schema.ResourceData, meta interface{}) *consulapi.ACLBindingRule {
_, _, wOpts := getClient(d, meta)
return &consulapi.ACLBindingRule{
bindingRule := &consulapi.ACLBindingRule{
ID: d.Id(),
Description: d.Get("description").(string),
AuthMethod: d.Get("auth_method").(string),
Expand All @@ -143,4 +168,17 @@ func getBindingRule(d *schema.ResourceData, meta interface{}) *consulapi.ACLBind
BindType: consulapi.BindingRuleBindType(d.Get("bind_type").(string)),
Namespace: wOpts.Namespace,
}

if bindVars, ok := d.GetOk("bind_vars.0"); ok {
tv := bindVars.(map[string]interface{})

processedVars := &consulapi.ACLTemplatedPolicyVariables{}
if tv["name"] != nil {
processedVars.Name = tv["name"].(string)
}

bindingRule.BindVars = processedVars
}

return bindingRule
}
67 changes: 67 additions & 0 deletions consul/resource_consul_acl_binding_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ func TestAccConsulACLBindingRule_basic(t *testing.T) {
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "bind_name", "minikube2"),
),
},
{
Config: testResourceACLBindingRuleConfig_templatedPolicyWithNoVariables,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "auth_method", "minikube2"),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "description", ""),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "selector", "serviceaccount.namespace==default2"),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "bind_type", "templated-policy"),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "bind_name", "builtin/dns"),
),
},
{
Config: testResourceACLBindingRuleConfig_templatedPolicyWithVariables,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "auth_method", "minikube2"),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "description", ""),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "selector", "serviceaccount.namespace==default2"),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "bind_type", "templated-policy"),
resource.TestCheckResourceAttr("consul_acl_binding_rule.test", "bind_name", "builtin/service"),
),
},
{
Config: testResourceACLBindingRuleConfig_wrongType,
ExpectError: regexp.MustCompile(`Invalid Binding Rule: unknown BindType "foobar"`),
Expand Down Expand Up @@ -225,6 +245,53 @@ resource "consul_acl_binding_rule" "test" {
bind_name = "minikube2"
}`

const testResourceACLBindingRuleConfig_templatedPolicyWithNoVariables = `
resource "consul_acl_auth_method" "test" {
name = "minikube2"
type = "kubernetes"
description = "dev minikube cluster"
config = {
Host = "https://192.0.2.42:8443"
CACert = <<-EOF
` + testCert + `
EOF
ServiceAccountJWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
}
resource "consul_acl_binding_rule" "test" {
auth_method = "${consul_acl_auth_method.test.name}"
selector = "serviceaccount.namespace==default2"
bind_type = "templated-policy"
bind_name = "builtin/dns"
}`

const testResourceACLBindingRuleConfig_templatedPolicyWithVariables = `
resource "consul_acl_auth_method" "test" {
name = "minikube2"
type = "kubernetes"
description = "dev minikube cluster"
config = {
Host = "https://192.0.2.42:8443"
CACert = <<-EOF
` + testCert + `
EOF
ServiceAccountJWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
}
resource "consul_acl_binding_rule" "test" {
auth_method = "${consul_acl_auth_method.test.name}"
selector = "serviceaccount.namespace==default2"
bind_type = "templated-policy"
bind_name = "builtin/service"
bind_vars {
name = "api"
}
}`

const testResourceACLBindingRuleConfig_wrongType = `
resource "consul_acl_auth_method" "test" {
name = "minikube2"
Expand Down
73 changes: 73 additions & 0 deletions consul/resource_consul_acl_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,43 @@ func resourceConsulACLRole() *schema.Resource {
},
},
},
"templated_policies": {
Type: schema.TypeList,
Optional: true,
Description: "The list of templated policies that should be applied to the token.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"template_name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the templated policies.",
},
"template_variables": {
Type: schema.TypeList,
MaxItems: 1,
Description: "The templated policy variables.",
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
Description: "The name of node, workload identity or service.",
},
},
},
},
"datacenters": {
Type: schema.TypeList,
Optional: true,
Description: "Specifies the datacenters the effective policy is valid within.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
"namespace": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -145,13 +182,23 @@ func resourceConsulACLRoleRead(d *schema.ResourceData, meta interface{}) error {
}
}

templatedPolicies := make([]interface{}, len(role.TemplatedPolicies))
for i, tp := range role.TemplatedPolicies {
templatedPolicies[i] = map[string]interface{}{
"template_name": tp.TemplateName,
"datacenters": tp.Datacenters,
"template_variables": getTemplateVariables(tp),
}
}

sw := newStateWriter(d)

sw.set("name", role.Name)
sw.set("description", role.Description)
sw.set("policies", policies)
sw.set("service_identities", serviceIdentities)
sw.set("node_identities", nodeIdentities)
sw.set("templated_policies", templatedPolicies)
sw.set("namespace", role.Namespace)
sw.set("partition", role.Partition)

Expand Down Expand Up @@ -224,5 +271,31 @@ func getRole(d *schema.ResourceData, meta interface{}) *consulapi.ACLRole {
})
}

templatedPolicies := []*consulapi.ACLTemplatedPolicy{}
for key, tp := range d.Get("templated_policies").([]interface{}) {
t := tp.(map[string]interface{})

datacenters := []string{}
for _, d := range t["datacenters"].([]interface{}) {
datacenters = append(datacenters, d.(string))
}

templatedPolicy := &consulapi.ACLTemplatedPolicy{
Datacenters: datacenters,
TemplateName: t["template_name"].(string),
}

if templatedVariables, ok := d.GetOk(fmt.Sprint("templated_policies.", key, ".template_variables.0")); ok {
tv := templatedVariables.(map[string]interface{})
templatedPolicy.TemplateVariables = &consulapi.ACLTemplatedPolicyVariables{}

if tv["name"] != nil {
templatedPolicy.TemplateVariables.Name = tv["name"].(string)
}
}
templatedPolicies = append(templatedPolicies, templatedPolicy)
}
role.TemplatedPolicies = templatedPolicies

return role
}
44 changes: 44 additions & 0 deletions consul/resource_consul_acl_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ func TestAccConsulACLRole_basic(t *testing.T) {
resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.#", "1"),
resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.3690720679.datacenters.#", "0"),
resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.3690720679.service_name", "foo"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.#", "2"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.datacenters.#", "1"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.datacenters.0", "world"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.template_variables.#", "1"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.template_variables.0.name", "web"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.template_name", "builtin/service"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.1.template_variables.#", "0"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.1.template_name", "builtin/dns"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.1.template_variables.#", "0"),
),
},
{
Expand All @@ -48,6 +57,15 @@ func TestAccConsulACLRole_basic(t *testing.T) {
resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.#", "1"),
resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.2708159462.datacenters.#", "0"),
resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.2708159462.service_name", "bar"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.#", "2"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.datacenters.#", "1"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.datacenters.0", "wide"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.template_variables.#", "1"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.template_variables.0.name", "api"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.0.template_name", "builtin/service"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.1.template_variables.#", "0"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.1.template_name", "builtin/dns"),
resource.TestCheckResourceAttr("consul_acl_role.test", "templated_policies.1.template_variables.#", "0"),
),
},
{
Expand Down Expand Up @@ -129,6 +147,19 @@ resource "consul_acl_role" "test" {
service_identities {
service_name = "foo"
}
templated_policies {
template_name = "builtin/service"
datacenters = ["world"]
template_variables {
name = "web"
}
}
templated_policies {
template_name = "builtin/dns"
datacenters = ["world"]
}
}`

const testResourceACLRoleConfigUpdate = `
Expand All @@ -143,6 +174,19 @@ resource "consul_acl_role" "test" {
node_name = "hello"
datacenter = "world"
}
templated_policies {
template_name = "builtin/service"
datacenters = ["wide"]
template_variables {
name = "api"
}
}
templated_policies {
template_name = "builtin/dns"
datacenters = ["wide"]
}
}`

const testResourceACLRoleConfigPolicyName = `
Expand Down
Loading

0 comments on commit c0a99e6

Please sign in to comment.