Skip to content

feat: add use_internal_ca_certs option for local_auth_endpoint #1626

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
67 changes: 34 additions & 33 deletions docs/resources/cluster_v2.md

Large diffs are not rendered by default.

108 changes: 105 additions & 3 deletions rancher2/resource_rancher2_cluster_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,35 @@ func resourceRancher2ClusterV2() *schema.Resource {
oldInterface, oldOk := oldObj.([]interface{})
newInterface, newOk := newObj.([]interface{})
if oldOk && newOk && len(newInterface) > 0 {
if m, ok := newInterface[0].(map[string]interface{}); ok {
if ca, ok := m["ca_certs"].(string); ok && ca != "" {
if use, ok := m["use_internal_ca_certs"].(bool); ok && use {
return fmt.Errorf("only one of \"ca_certs\" or \"use_internal_ca_certs\" can be set")
}
}
}
oldConfig := expandClusterV2LocalAuthEndpoint(oldInterface)
newConfig := expandClusterV2LocalAuthEndpoint(newInterface)
if reflect.DeepEqual(oldConfig, newConfig) {
oldUse := false
newUse := false
if len(oldInterface) > 0 {
if m, ok := oldInterface[0].(map[string]interface{}); ok {
if v, ok := m["use_internal_ca_certs"].(bool); ok {
oldUse = v
}
}
}
if len(newInterface) > 0 {
if m, ok := newInterface[0].(map[string]interface{}); ok {
if v, ok := m["use_internal_ca_certs"].(bool); ok {
newUse = v
}
}
}
if reflect.DeepEqual(oldConfig, newConfig) && oldUse == newUse {
d.Clear("local_auth_endpoint")
} else {
d.SetNew("local_auth_endpoint", flattenClusterV2LocalAuthEndpoint(newConfig))
d.SetNew("local_auth_endpoint", newObj)
}
}
}
Expand Down Expand Up @@ -110,6 +133,15 @@ func resourceRancher2ClusterV2Create(d *schema.ResourceData, meta interface{}) e
return err
}

useInternal := false
if v, ok := d.Get("local_auth_endpoint").([]interface{}); ok && len(v) > 0 {
if m, ok := v[0].(map[string]interface{}); ok {
if b, ok := m["use_internal_ca_certs"].(bool); ok {
useInternal = b
}
}
}

log.Printf("[INFO] Creating Cluster V2 %s", name)

newCluster, err := createClusterV2(meta.(*Config), cluster)
Expand All @@ -130,6 +162,18 @@ func resourceRancher2ClusterV2Create(d *schema.ResourceData, meta interface{}) e
}
}

if useInternal {
caCert, err := getClusterCACert(meta.(*Config), newCluster.Status.ClusterName)
if err != nil {
return err
}
newCluster.Spec.LocalClusterAuthEndpoint.CACerts = caCert
_, err = updateClusterV2(meta.(*Config), newCluster.ID, newCluster)
if err != nil {
return err
}
}

return resourceRancher2ClusterV2Read(d, meta)
}

Expand All @@ -150,7 +194,10 @@ func resourceRancher2ClusterV2Read(d *schema.ResourceData, meta interface{}) err
if err != nil {
return err
}
return flattenClusterV2(d, cluster)
if err := flattenClusterV2(d, cluster); err != nil {
return err
}
return setClusterV2LocalAuthEndpointInternalFlag(d, meta.(*Config), cluster)
}

func resourceRancher2ClusterV2Update(d *schema.ResourceData, meta interface{}) error {
Expand All @@ -159,6 +206,18 @@ func resourceRancher2ClusterV2Update(d *schema.ResourceData, meta interface{}) e
return err
}

if v, ok := d.Get("local_auth_endpoint").([]interface{}); ok && len(v) > 0 {
if m, ok := v[0].(map[string]interface{}); ok {
if b, ok := m["use_internal_ca_certs"].(bool); ok && b {
caCert, err := getClusterCACert(meta.(*Config), d.Get("cluster_v1_id").(string))
if err != nil {
return err
}
cluster.Spec.LocalClusterAuthEndpoint.CACerts = caCert
}
}
}

log.Printf("[INFO] Updating Cluster V2 %s", d.Id())

newCluster, err := updateClusterV2(meta.(*Config), d.Id(), cluster)
Expand Down Expand Up @@ -420,3 +479,46 @@ func setClusterV2LegacyData(d *schema.ResourceData, c *Config) error {

return nil
}

func getClusterCACert(c *Config, clusterV1ID string) (string, error) {
if c == nil {
return "", fmt.Errorf("provider config is nil")
}
if clusterV1ID == "" {
return "", fmt.Errorf("cluster_v1_id is empty")
}
client, err := c.ManagementClient()
if err != nil {
return "", err
}
cluster := &Cluster{}
err = client.APIBaseClient.ByID(managementClient.ClusterType, clusterV1ID, cluster)
if err != nil {
return "", err
}
return decodeCACertIfBase64(cluster.CACert), nil
}

func setClusterV2LocalAuthEndpointInternalFlag(d *schema.ResourceData, c *Config, cluster *ClusterV2) error {
if cluster == nil || c == nil {
return fmt.Errorf("setting local auth endpoint internal flag: missing data")
}
lae := cluster.Spec.LocalClusterAuthEndpoint
useInternal := false
if cluster.Status.ClusterName != "" && lae.CACerts != "" {
caCert, err := getClusterCACert(c, cluster.Status.ClusterName)
if err != nil {
return err
}
if lae.CACerts == caCert {
useInternal = true
}
}
if v, ok := d.Get("local_auth_endpoint").([]interface{}); ok && len(v) > 0 {
if m, ok := v[0].(map[string]interface{}); ok {
m["use_internal_ca_certs"] = useInternal
d.Set("local_auth_endpoint", []interface{}{m})
}
}
return nil
}
6 changes: 6 additions & 0 deletions rancher2/schema_cluster_v2_rke_config_local_auth_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ func clusterV2LocalAuthEndpointFields() map[string]*schema.Schema {
"ca_certs": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"enabled": {
Type: schema.TypeBool,
Expand All @@ -21,6 +22,11 @@ func clusterV2LocalAuthEndpointFields() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
},
"use_internal_ca_certs": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
}

return s
Expand Down
24 changes: 21 additions & 3 deletions rancher2/structure_cluster_v2_local_auth_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
)

var (
testClusterV2LocalAuthEndpointConf rkev1.LocalClusterAuthEndpoint
testClusterV2LocalAuthEndpointInterface []interface{}
testClusterV2LocalAuthEndpointConf rkev1.LocalClusterAuthEndpoint
testClusterV2LocalAuthEndpointInterface []interface{}
testClusterV2LocalAuthEndpointInterfaceUseInternal []interface{}
testClusterV2LocalAuthEndpointInterfaceWithFlag []interface{}
)

func init() {
Expand All @@ -26,6 +28,22 @@ func init() {
"fqdn": "fqdn",
},
}
testClusterV2LocalAuthEndpointInterfaceUseInternal = []interface{}{
map[string]interface{}{
"ca_certs": "ca_certs",
"enabled": true,
"fqdn": "fqdn",
"use_internal_ca_certs": true,
},
}
testClusterV2LocalAuthEndpointInterfaceWithFlag = []interface{}{
map[string]interface{}{
"ca_certs": "ca_certs",
"enabled": true,
"fqdn": "fqdn",
"use_internal_ca_certs": false,
},
}
}

func TestFlattenClusterV2LocalAuthEndpoint(t *testing.T) {
Expand Down Expand Up @@ -53,7 +71,7 @@ func TestExpandClusterV2LocalAuthEndpoint(t *testing.T) {
ExpectedOutput rkev1.LocalClusterAuthEndpoint
}{
{
testClusterV2LocalAuthEndpointInterface,
testClusterV2LocalAuthEndpointInterfaceUseInternal,
testClusterV2LocalAuthEndpointConf,
},
}
Expand Down
2 changes: 1 addition & 1 deletion rancher2/structure_cluster_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func init() {
"name": "name",
"fleet_namespace": "fleet_namespace",
"kubernetes_version": "kubernetes_version",
"local_auth_endpoint": testClusterV2LocalAuthEndpointInterface,
"local_auth_endpoint": testClusterV2LocalAuthEndpointInterfaceWithFlag,
"rke_config": testClusterV2RKEConfigInterface,
"agent_env_vars": testClusterV2EnvVarInterface,
"cluster_agent_deployment_customization": testClusterV2ClusterAgentCustomizationInterface,
Expand Down
13 changes: 13 additions & 0 deletions rancher2/util_certs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package rancher2

import "encoding/base64"

func decodeCACertIfBase64(cert string) string {
if cert == "" {
return cert
}
if b, err := base64.StdEncoding.DecodeString(cert); err == nil {
return string(b)
}
return cert
}
17 changes: 17 additions & 0 deletions rancher2/util_certs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package rancher2

import (
"encoding/base64"
"testing"
)

func TestDecodeCACertIfBase64(t *testing.T) {
pem := "-----BEGIN CERTIFICATE-----\nFAKE\n-----END CERTIFICATE-----\n"
encoded := base64.StdEncoding.EncodeToString([]byte(pem))
if got := decodeCACertIfBase64(encoded); got != pem {
t.Fatalf("expected decoded cert, got %q", got)
}
if got := decodeCACertIfBase64(pem); got != pem {
t.Fatalf("expected unchanged cert, got %q", got)
}
}