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 parameters support to MKS #318

Open
wants to merge 8 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
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/selectel/domains-go v1.0.2
github.com/selectel/go-selvpcclient/v4 v4.0.0
github.com/selectel/iam-go v0.4.1
github.com/selectel/mks-go v0.17.0
github.com/selectel/mks-go v0.18.0
github.com/selectel/secretsmanager-go v0.2.1
github.com/stretchr/testify v1.8.4
)
Expand Down Expand Up @@ -59,7 +59,7 @@ require (
github.com/vmihailenco/tagparser v0.1.1 // indirect
github.com/zclconf/go-cty v1.12.1 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ github.com/selectel/go-selvpcclient/v4 v4.0.0 h1:5HorF8n6u/4BUh2+cJEysmXhMOB9epG
github.com/selectel/go-selvpcclient/v4 v4.0.0/go.mod h1:eFhL1KUW159KOJVeGO7k/Uxl0TYd/sBkWXjuF5WxmYk=
github.com/selectel/iam-go v0.4.1 h1:grncCGkPVCM6nwqSTk+q15M5ZO6S/Pe0AIbbmKtm6gU=
github.com/selectel/iam-go v0.4.1/go.mod h1:OIAkW7MZK97YUm+uvUgYbgDhkI9SdzTCxwd4yZoOR1o=
github.com/selectel/mks-go v0.17.0 h1:fYyIuB/K+TJJDy50Bl7z52SrogYCdekpKPaRc0pDi+M=
github.com/selectel/mks-go v0.17.0/go.mod h1:VxtV3dzwgOEzZc+9VMQb9DvxfSlej2ZQ8jnT8kqIGgU=
github.com/selectel/mks-go v0.18.0 h1:RBoke/rnLtmgGxi6/U16YSF2Y9yE3W0GsqugGXGP/C8=
github.com/selectel/mks-go v0.18.0/go.mod h1:VxtV3dzwgOEzZc+9VMQb9DvxfSlej2ZQ8jnT8kqIGgU=
github.com/selectel/secretsmanager-go v0.2.1 h1:OSBrA/07lm/Ecpwg59IJHFAoUHZR29oyfwUgTpr/dos=
github.com/selectel/secretsmanager-go v0.2.1/go.mod h1:DUPexhiJWLTyZEvse7grJWdcA8p8TEI93gNu1dDu7Yg=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
Expand Down Expand Up @@ -228,8 +228,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
46 changes: 46 additions & 0 deletions selectel/mks.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,17 @@ func flattenAdmissionControllersFromSlice(kubeVersion string, admissionControlle
return availableAdmissionControllers
}

func flattenMKSClusterV1OIDC(view *cluster.View) []interface{} {
return []interface{}{map[string]interface{}{
"enabled": view.KubernetesOptions.OIDC.Enabled,
"provider_name": view.KubernetesOptions.OIDC.ProviderName,
"issuer_url": view.KubernetesOptions.OIDC.IssuerURL,
"client_id": view.KubernetesOptions.OIDC.ClientID,
"username_claim": view.KubernetesOptions.OIDC.UsernameClaim,
"groups_claim": view.KubernetesOptions.OIDC.GroupsClaim,
}}
}

func expandMKSNodegroupV1Taints(taints []interface{}) []nodegroup.Taint {
result := make([]nodegroup.Taint, len(taints))
for i := range taints {
Expand Down Expand Up @@ -540,6 +551,41 @@ func expandMKSNodegroupV1Labels(labels map[string]interface{}) map[string]string
return result
}

func expandAndValidateMKSClusterV1OIDC(d *schema.ResourceData) (cluster.OIDC, error) {
nestedResource := d.Get("oidc").([]any)
if len(nestedResource) == 0 {
return cluster.OIDC{}, nil
}

// Resource always comes with only first element because of validation
resourceMap := nestedResource[0].(map[string]interface{})
oidc := cluster.OIDC{
Enabled: resourceMap["enabled"].(bool),
ProviderName: resourceMap["provider_name"].(string),
IssuerURL: resourceMap["issuer_url"].(string),
ClientID: resourceMap["client_id"].(string),
UsernameClaim: resourceMap["username_claim"].(string),
GroupsClaim: resourceMap["groups_claim"].(string),
}

if oidc.Enabled {
for _, s := range []string{oidc.ProviderName, oidc.IssuerURL, oidc.ClientID} {
if s == "" {
return cluster.OIDC{}, errors.New("\"provider_name\", \"issuer_url\" and \"client_id\" " +
"should not be empty in case of enabled oidc")
}
}
} else {
for _, s := range []string{oidc.ProviderName, oidc.IssuerURL, oidc.ClientID, oidc.UsernameClaim, oidc.GroupsClaim} {
if s != "" {
return cluster.OIDC{}, errors.New("oidc params cannot be configured if it is disabled")
}
}
}

return oidc, nil
}

func getMKSClient(d *schema.ResourceData, meta interface{}) (*v1.ServiceClient, diag.Diagnostics) {
config := meta.(*Config)
projectID := d.Get("project_id").(string)
Expand Down
60 changes: 60 additions & 0 deletions selectel/resource_selectel_mks_cluster_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,51 @@ func resourceMKSClusterV1() *schema.Resource {
Default: false,
ForceNew: false,
},
"oidc": {
Type: schema.TypeList,
Optional: true,
ForceNew: false,
MaxItems: 1,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Required: true,
},
"provider_name": {
Type: schema.TypeString,
Required: true,
},
"issuer_url": {
Type: schema.TypeString,
Required: true,
},
"client_id": {
Type: schema.TypeString,
Required: true,
},
"username_claim": {
Type: schema.TypeString,
Optional: true,
Default: "",
DiffSuppressFunc: func(_, oldVersion, newVersion string, _ *schema.ResourceData) bool {
// Ignore diff on default value from API.
return oldVersion == "sub" && newVersion == ""
},
},
"groups_claim": {
Type: schema.TypeString,
Optional: true,
Default: "",
DiffSuppressFunc: func(_, oldVersion, newVersion string, _ *schema.ResourceData) bool {
// Ignore diff on default value from API.
return oldVersion == "groups" && newVersion == ""
},
},
},
},
},
},
}
}
Expand Down Expand Up @@ -199,6 +244,11 @@ func resourceMKSClusterV1Create(ctx context.Context, d *schema.ResourceData, met
return diag.FromErr(errCreatingObject(objectCluster, err))
}

oidc, err := expandAndValidateMKSClusterV1OIDC(d)
if err != nil {
return diag.FromErr(err)
}

createOpts := &cluster.CreateOpts{
Name: d.Get("name").(string),
NetworkID: d.Get("network_id").(string),
Expand All @@ -215,6 +265,7 @@ func resourceMKSClusterV1Create(ctx context.Context, d *schema.ResourceData, met
AuditLogs: cluster.AuditLogs{
Enabled: enableAuditLogs,
},
OIDC: oidc,
},
Zonal: &zonal,
PrivateKubeAPI: &privateKubeAPI,
Expand Down Expand Up @@ -265,6 +316,7 @@ func resourceMKSClusterV1Read(ctx context.Context, d *schema.ResourceData, meta

return diag.FromErr(errGettingObject(objectCluster, d.Id(), err))
}
log.Printf("[TEST] test read oidc: %v ", d.Get("oidc"))

d.Set("name", mksCluster.Name)
d.Set("status", mksCluster.Status)
Expand All @@ -282,6 +334,7 @@ func resourceMKSClusterV1Read(ctx context.Context, d *schema.ResourceData, meta
d.Set("zonal", mksCluster.Zonal)
d.Set("private_kube_api", mksCluster.PrivateKubeAPI)
d.Set("enable_audit_logs", mksCluster.KubernetesOptions.AuditLogs.Enabled)
d.Set("oidc", flattenMKSClusterV1OIDC(mksCluster))

return nil
}
Expand Down Expand Up @@ -334,6 +387,13 @@ func resourceMKSClusterV1Update(ctx context.Context, d *schema.ResourceData, met
v := d.Get("enable_audit_logs").(bool)
kubeOptions.AuditLogs.Enabled = v
}
if d.HasChange("oidc") {
oidc, err := expandAndValidateMKSClusterV1OIDC(d)
if err != nil {
return diag.FromErr(err)
}
kubeOptions.OIDC = oidc
}

updateOpts.KubernetesOptions = kubeOptions

Expand Down
35 changes: 35 additions & 0 deletions selectel/resource_selectel_mks_cluster_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ func TestAccMKSClusterV1Basic(t *testing.T) {
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "feature_gates.0", defaultFeatureGates[0]),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "admission_controllers.0", defaultAdmissionControllers[0]),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "enable_audit_logs", "false"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.enabled", "false"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.provider_name", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.issuer_url", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.client_id", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.username_claim", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.groups_claim", ""),
),
},
{
Expand All @@ -73,6 +79,12 @@ func TestAccMKSClusterV1Basic(t *testing.T) {
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "feature_gates.0", defaultFeatureGates[1]),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "admission_controllers.0", defaultAdmissionControllers[1]),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "enable_audit_logs", "true"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.enabled", "true"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.provider_name", "kubernetes"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.issuer_url", "https://keycloak.example.com/realms/kubernetes"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.client_id", "test"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.username_claim", "email"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.groups_claim", "groups"),
),
},
},
Expand Down Expand Up @@ -110,6 +122,12 @@ func TestAccMKSClusterV1Zonal(t *testing.T) {
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "maintenance_window_start", maintenanceWindowStart),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "status", "ACTIVE"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "enable_audit_logs", "true"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.enabled", "true"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.provider_name", "kubernetes"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.issuer_url", "https://keycloak.example.com/realms/kubernetes"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.client_id", "test"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.username_claim", "email"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.groups_claim", "groups"),
),
},
},
Expand Down Expand Up @@ -147,6 +165,12 @@ func TestAccMKSClusterV1PrivateKubeAPI(t *testing.T) {
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "maintenance_window_start", maintenanceWindowStart),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "status", "ACTIVE"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "enable_audit_logs", "false"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.enabled", "false"),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.provider_name", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.issuer_url", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.client_id", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.username_claim", ""),
resource.TestCheckResourceAttr("selectel_mks_cluster_v1.cluster_tf_acc_test_1", "oidc.0.groups_claim", ""),
),
},
},
Expand Down Expand Up @@ -312,6 +336,14 @@ func testAccMKSClusterV1Zonal(projectName, clusterName, kubeVersion, maintenance
enable_patch_version_auto_upgrade = false
zonal = true
enable_audit_logs = true
oidc {
enabled = true
provider_name = "kubernetes"
client_id = "test"
issuer_url = "https://keycloak.example.com/realms/kubernetes"
username_claim = "email"
groups_claim = "groups"
}
}`, projectName, clusterName, kubeVersion, maintenanceWindowStart)
}

Expand All @@ -330,6 +362,9 @@ func testAccMKSClusterV1PrivateKubeAPI(projectName, clusterName, kubeVersion, ma
zonal = false
private_kube_api = true
enable_audit_logs = false
oidc {
enabled = false
}
}`, projectName, clusterName, kubeVersion, maintenanceWindowStart)
}

Expand Down
28 changes: 22 additions & 6 deletions website/docs/r/mks_cluster_v1.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ resource "selectel_mks_cluster_v1" "basic_cluster" {
* `region` - (Required) Pool where the cluster is located, for example, `ru-7`. Changing this creates a new cluster. Learn more about available pools in the [Availability matrix](https://docs.selectel.ru/en/control-panel-actions/availability-matrix/#managed-kubernetes).

* `kube_version` - (Required) Kubernetes version of the cluster. Changing this upgrades the cluster version. You can retrieve information about the Kubernetes versions with the [selectel_mks_kube_versions_v1](https://registry.terraform.io/providers/selectel/selectel/latest/docs/data-sources/mks_kube_versions_v1) data source.

To upgrade a patch version, the desired version should match the latest available patch version for the current minor release.

To upgrade a minor version, the desired version should match the next available minor release with the latest patch version.

* `zonal` - (Optional) Specifies a cluster type. Changing this creates a new cluster.

Boolean flag:

* `false` (default) - for a high availability cluster with three master nodes located on different hosts in one pool segment.

* `true` - for a basic cluster with one master node. Set `enable_patch_version_auto_upgrade` to `false`.

Learn more about [Cluster types](https://docs.selectel.ru/en/cloud/managed-kubernetes/about/about-managed-kubernetes/#cluster-types).
Expand All @@ -79,7 +79,7 @@ resource "selectel_mks_cluster_v1" "basic_cluster" {
Boolean flag:

* `false` (default) - Kube API is available from the Internet;

* `true` - Kube API is available only from the cluster network.

* `enable_audit_logs` - (Optional) Enables or disables collection of audit logs. Learn how to [configure export of audit logs to a logging system](https://docs.selectel.ru/en/cloud/managed-kubernetes/clusters/logs/#configure-export-of-audit-logs).
Expand All @@ -90,6 +90,22 @@ resource "selectel_mks_cluster_v1" "basic_cluster" {

* `true` - Audit logs are collected and available for export.

* `oidc` - (Optional) Connects an OpenID Connect (OIDC) provider to the cluster. Learn how to [configure the OIDC provider in the cluster](https://docs.selectel.ru/en/cloud/managed-kubernetes/clusters/access-to-cluster-with-oidc-provider/#configure-oidc-connection).

The block supports the following arguments:

* `enabled` - (Required) Enables or disables authentication with OpenID Connect in the cluster.

* `provider_name` - (Required) Name of the connection that you create. The name is only for identification purposes.

* `issuer_url` - (Required) URL of the OIDC provider used to authenticate users who request access to the cluster. The link must start with `https://`.

* `client_id` - (Required) Service identifier issued by the OIDC provider and used in authentication requests to the resources.

* `username_claim` - JWT claim to use as the username. The default value is `sub`. The content of the claim must be a unique identifier of the end user.

* `groups_claim` - JWT claim to use as the user's group. The default value is `groups`.

## Attributes Reference

* `maintenance_window_end` - Time in UTC when maintenance in the cluster ends. The format is `hh:mm:ss`. Learn more about the [Maintenance window](https://docs.selectel.ru/en/cloud/managed-kubernetes/clusters/set-up-maintenance-window/).
Expand Down Expand Up @@ -117,7 +133,7 @@ where:

* `<username>` — Name of the service user. To get the name, in the [Control panel](https://my.selectel.ru/iam/users_management/users?type=service), go to **Identity & Access Management** ⟶ **User management** ⟶ the **Service users** tab ⟶ copy the name of the required user. Learn more about [Service users](https://docs.selectel.ru/en/control-panel-actions/users-and-roles/user-types-and-roles/).

* `<password>` — Password of the service user.
* `<password>` — Password of the service user.

* `<selectel_project_id>` — Unique identifier of the associated project. To get the ID, in the [Control panel](https://my.selectel.ru/vpc/mks), go to **Cloud Platform** ⟶ project name ⟶ copy the ID of the required project. Learn more about [Projects](https://docs.selectel.ru/en/cloud/managed-kubernetes/about/projects/).

Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/mks_nodegroup_v1.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Boolean flag:

* `nodes` - List of nodes in the node group.

* `nodegroup_type` - Type of the node group. Available values are `STANDARD`, `GPU`, and `SGX`.
* `nodegroup_type` - Type of the node group. Available values are `STANDARD` and `GPU`.

## Import

Expand Down
Loading