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 12, 2023
1 parent ba52b81 commit d246e07
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 15 deletions.
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
84 changes: 84 additions & 0 deletions consul/resource_consul_acl_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,43 @@ func resourceConsulACLToken() *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,
},
},
},
},
},
"local": {
Type: schema.TypeBool,
ForceNew: true,
Expand Down Expand Up @@ -189,13 +226,23 @@ func resourceConsulACLTokenRead(d *schema.ResourceData, meta interface{}) error
}
}

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

sw := newStateWriter(d)
sw.set("accessor_id", aclToken.AccessorID)
sw.set("description", aclToken.Description)
sw.set("policies", policies)
sw.set("roles", roles)
sw.set("service_identities", serviceIdentities)
sw.set("node_identities", nodeIdentities)
sw.set("templated_policies", templatedPolicies)
sw.set("local", aclToken.Local)
sw.set("expiration_time", expirationTime)
sw.set("namespace", aclToken.Namespace)
Expand All @@ -204,6 +251,16 @@ func resourceConsulACLTokenRead(d *schema.ResourceData, meta interface{}) error
return sw.error()
}

func getTemplateVariables(templatedPolicy *consulapi.ACLTemplatedPolicy) []map[string]interface{} {
if templatedPolicy == nil || templatedPolicy.TemplateVariables == nil {
return nil
}

return []map[string]interface{}{
{"name": templatedPolicy.TemplateVariables.Name},
}
}

func resourceConsulACLTokenUpdate(d *schema.ResourceData, meta interface{}) error {
client, _, wOpts := getClient(d, meta)

Expand Down Expand Up @@ -289,6 +346,33 @@ func getToken(d *schema.ResourceData) *consulapi.ACLToken {
}
aclToken.NodeIdentities = nodeIdentities

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)
}
aclToken.TemplatedPolicies = templatedPolicies

expirationTime := d.Get("expiration_time").(string)
if expirationTime != "" {
// the string has already been validated so there is no need to check
Expand Down
23 changes: 23 additions & 0 deletions consul/resource_consul_acl_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestAccConsulACLToken_basic(t *testing.T) {
resource.TestCheckResourceAttr("consul_acl_token.test", "node_identities.#", "0"),
resource.TestCheckResourceAttrSet("consul_acl_token.test", "policies.#"),
resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.#", "0"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.#", "0"),
),
},
{
Expand All @@ -64,6 +65,14 @@ func TestAccConsulACLToken_basic(t *testing.T) {
resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.0.datacenters.#", "1"),
resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.0.datacenters.0", "world"),
resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.0.service_name", "hello"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.#", "2"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.0.datacenters.#", "1"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.0.datacenters.0", "world"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.0.template_variables.#", "1"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.0.template_variables.0.name", "web"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.0.template_name", "builtin/service"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.1.template_variables.#", "0"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.1.template_name", "builtin/dns"),
),
},
{
Expand All @@ -82,6 +91,7 @@ func TestAccConsulACLToken_basic(t *testing.T) {
resource.TestCheckResourceAttr("consul_acl_token.test", "roles.#", "1"),
resource.TestCheckResourceAttr("consul_acl_token.test", "roles.1785148924", "test"),
resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.#", "0"),
resource.TestCheckResourceAttr("consul_acl_token.test", "templated_policies.#", "0"),
),
},
},
Expand Down Expand Up @@ -189,6 +199,19 @@ resource "consul_acl_token" "test" {
node_name = "foo"
datacenter = "bar"
}
templated_policies {
template_name = "builtin/service"
datacenters = ["world"]
template_variables {
name = "web"
}
}
templated_policies {
template_name = "builtin/dns"
datacenters = ["world"]
}
}`

const testResourceACLTokenConfigRole = `
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/hashicorp/terraform-provider-consul

require (
github.com/hashicorp/consul/api v1.23.0
github.com/hashicorp/consul/api v1.26.1-rc1
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/terraform-plugin-sdk v1.17.2
github.com/mitchellh/mapstructure v1.5.0
Expand All @@ -12,7 +12,7 @@ require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.12.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
)

require (
Expand All @@ -39,7 +39,7 @@ require (
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.7.1 // indirect
github.com/hashicorp/consul/sdk v0.14.0
github.com/hashicorp/consul/sdk v0.14.3-rc1
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.0 // indirect
Expand Down Expand Up @@ -88,9 +88,9 @@ require (
github.com/zclconf/go-cty-yaml v1.0.2 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/net v0.13.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.114.0 // indirect
Expand Down
Loading

0 comments on commit d246e07

Please sign in to comment.