Skip to content

Commit acbbaa4

Browse files
dranicuts-mini
andauthored
OIDC feature (#423)
* feat: adding oidc features to cluster-api * added webhook for oidc feature and corrected conversion corrected image path * Fixed webhook and added webhook tests. * revert changes to manager_image_patch file * removed unecessary formatting changes * added OIDC doc * corrected formatt * added unit test for compareSpecs --------- Co-authored-by: Tyler Horvath <tyler.horvath@gmail.com>
1 parent 8738a4f commit acbbaa4

24 files changed

+807
-37
lines changed

api/v1beta1/conversion.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,8 @@ func Convert_v1beta1_OCIManagedClusterStatus_To_v1beta2_OCIManagedClusterStatus(
142142
func Convert_v1beta2_OCIManagedClusterSpec_To_v1beta1_OCIManagedClusterSpec(in *v1beta2.OCIManagedClusterSpec, out *OCIManagedClusterSpec, s conversion.Scope) error {
143143
return autoConvert_v1beta2_OCIManagedClusterSpec_To_v1beta1_OCIManagedClusterSpec(in, out, s)
144144
}
145+
146+
// Convert_v1beta2_ClusterOptions_To_v1beta1_ClusterOptions converts v1beta2 ClusterOptions to v1beta1 ClusterOptions
147+
func Convert_v1beta2_ClusterOptions_To_v1beta1_ClusterOptions(in *v1beta2.ClusterOptions, out *ClusterOptions, s conversion.Scope) error {
148+
return autoConvert_v1beta2_ClusterOptions_To_v1beta1_ClusterOptions(in, out, s)
149+
}

api/v1beta1/ocimanagedcontrolplane_conversion.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ func (src *OCIManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
3636
dst.Spec.ClusterType = restored.Spec.ClusterType
3737
dst.Spec.Addons = restored.Spec.Addons
3838
dst.Status.AddonStatus = restored.Status.AddonStatus
39+
40+
// Handle ClusterOption conversion
41+
// Copy OpenIdConnectDiscovery if present
42+
if restored.Spec.ClusterOption.OpenIdConnectDiscovery != nil {
43+
if dst.Spec.ClusterOption.OpenIdConnectDiscovery == nil {
44+
dst.Spec.ClusterOption.OpenIdConnectDiscovery = &v1beta2.OpenIDConnectDiscovery{}
45+
}
46+
dst.Spec.ClusterOption.OpenIdConnectDiscovery.IsOpenIdConnectDiscoveryEnabled =
47+
restored.Spec.ClusterOption.OpenIdConnectDiscovery.IsOpenIdConnectDiscoveryEnabled
48+
}
49+
50+
// Copy OpenIdConnectTokenAuthenticationConfig if present
51+
if restored.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig != nil {
52+
if dst.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig == nil {
53+
dst.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig = &v1beta2.OpenIDConnectTokenAuthenticationConfig{}
54+
}
55+
*dst.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig =
56+
*restored.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig
57+
}
58+
3959
return nil
4060
}
4161

api/v1beta1/zz_generated.conversion.go

Lines changed: 7 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1beta2/ocimanagedcontrolplane_types.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1beta2
1818

1919
import (
20+
"github.com/oracle/oci-go-sdk/v65/containerengine"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2223
)
@@ -122,8 +123,66 @@ type ClusterOptions struct {
122123
// AdmissionControllerOptions defines the properties that define supported admission controllers.
123124
// +optional
124125
AdmissionControllerOptions *AdmissionControllerOptions `json:"admissionControllerOptions,omitempty"`
126+
127+
// OpenIDConnectDiscovery specifies OIDC discovery settings
128+
// +optional
129+
OpenIdConnectDiscovery *OpenIDConnectDiscovery `json:"openIdConnectDiscovery,omitempty"`
130+
131+
//OpenIDConnectTokenAuthenticationConfig
132+
// +optional
133+
OpenIdConnectTokenAuthenticationConfig *OpenIDConnectTokenAuthenticationConfig `json:"openIdConnectTokenAuthenticationConfig,omitempty"`
134+
}
135+
136+
type OpenIDConnectDiscovery struct {
137+
// IsOpenIDConnectDiscoveryEnabled defines whether or not to enable the OIDC discovery.
138+
// +optional
139+
IsOpenIdConnectDiscoveryEnabled *bool `json:"isOpenIdConnectDiscoveryEnabled,omitempty"`
140+
}
141+
142+
type OpenIDConnectTokenAuthenticationConfig struct {
143+
// A Base64 encoded public RSA or ECDSA certificates used to sign your identity provider's web certificate.
144+
// +optional
145+
CaCertificate *string `json:"caCertificate,omitempty"`
146+
147+
// A client id that all tokens must be issued for.
148+
// +optional
149+
ClientId *string `json:"clientId,omitempty"`
150+
151+
// JWT claim to use as the user's group. If the claim is present it must be an array of strings.
152+
// +optional
153+
GroupsClaim *string `json:"groupsClaim,omitempty"`
154+
155+
// Prefix prepended to group claims to prevent clashes with existing names (such as system:groups).
156+
// +optional
157+
GroupsPrefix *string `json:"groupsPrefix,omitempty"`
158+
159+
// IsOpenIdConnectAuthEnabled defines whether or not to enable the OIDC authentication.
160+
IsOpenIdConnectAuthEnabled bool `json:"isOpenIdConnectAuthEnabled"`
161+
162+
// URL of the provider that allows the API server to discover public signing keys. Only URLs that use the https:// scheme are accepted. This is typically the provider's discovery URL, changed to have an empty path.
163+
// +optional
164+
IssuerUrl *string `json:"issuerUrl,omitempty"`
165+
166+
// A key=value pair that describes a required claim in the ID Token. If set, the claim is verified to be present in the ID Token with a matching value. Repeat this flag to specify multiple claims.
167+
// +optional
168+
RequiredClaims []KeyValue `json:"requiredClaims,omitempty"`
169+
170+
// The signing algorithms accepted. Default is ["RS256"].
171+
// +optional
172+
SigningAlgorithms []string `json:"signingAlgorithms,omitempty"`
173+
174+
// JWT claim to use as the user name. By default sub, which is expected to be a unique identifier of the end user. Admins can choose other claims, such as email or name, depending on their provider. However, claims other than email will be prefixed with the issuer URL to prevent naming clashes with other plugins.
175+
// +optional
176+
UsernameClaim *string `json:"usernameClaim,omitempty"`
177+
178+
// Prefix prepended to username claims to prevent clashes with existing names (such as system:users). For example, the value oidc: will create usernames like oidc:jane.doe. If this flag isn't provided and --oidc-username-claim is a value other than email the prefix defaults to ( Issuer URL )# where ( Issuer URL ) is the value of --oidc-issuer-url. The value - can be used to disable all prefixing.
179+
// +optional
180+
UsernamePrefix *string `json:"usernamePrefix,omitempty"`
125181
}
126182

183+
// KeyValue defines the properties that define a key value pair. This is alias to containerengine.KeyValue, to support the sdk type
184+
type KeyValue containerengine.KeyValue
185+
127186
// AddOnOptions defines the properties that define options for supported add-ons.
128187
type AddOnOptions struct {
129188
// IsKubernetesDashboardEnabled defines whether or not to enable the Kubernetes Dashboard add-on.

api/v1beta2/ocimanagedcontrolplane_webhook.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ func (c *OCIManagedControlPlane) ValidateCreate() (admission.Warnings, error) {
5656
if len(c.Name) > 31 {
5757
allErrs = append(allErrs, field.Invalid(field.NewPath("Name"), c.Name, "Name cannot be more than 31 characters"))
5858
}
59+
60+
if c.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig != nil && c.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig.IsOpenIdConnectAuthEnabled {
61+
if c.Spec.ClusterType != EnhancedClusterType {
62+
allErrs = append(allErrs, field.Invalid(field.NewPath("ClusterType"), c.Spec.ClusterType, "ClusterType needs to be set to ENHANCED_CLUSTER for OpenIdConnectTokenAuthenticationConfig to be enabled."))
63+
}
64+
if c.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig.ClientId == nil {
65+
allErrs = append(allErrs, field.Invalid(field.NewPath("ClientId"), c.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig.ClientId, "ClientId cannot be empty when OpenIdConnectAuth is enabled."))
66+
}
67+
if c.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig.IssuerUrl == nil {
68+
allErrs = append(allErrs, field.Invalid(field.NewPath("IssuerUrl "), c.Spec.ClusterOption.OpenIdConnectTokenAuthenticationConfig.IssuerUrl, "IssuerUrl cannot be empty when OpenIdConnectAuth is enabled."))
69+
}
70+
}
5971
if len(allErrs) == 0 {
6072
return nil, nil
6173
}

api/v1beta2/ocimanagedcontrolplane_webhook_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"strings"
2121
"testing"
2222

23+
"github.com/oracle/oci-go-sdk/v65/common"
24+
2325
"github.com/onsi/gomega"
2426
. "github.com/onsi/gomega"
2527
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -79,6 +81,85 @@ func TestOCIManagedControlPlane_ValidateCreate(t *testing.T) {
7981
},
8082
expectErr: false,
8183
},
84+
{
85+
name: "OpenIdConnectAuthEnabledWithValidConfig",
86+
c: &OCIManagedControlPlane{
87+
Spec: OCIManagedControlPlaneSpec{
88+
ClusterType: EnhancedClusterType,
89+
ClusterOption: ClusterOptions{
90+
OpenIdConnectTokenAuthenticationConfig: &OpenIDConnectTokenAuthenticationConfig{
91+
IsOpenIdConnectAuthEnabled: *common.Bool(true),
92+
ClientId: common.String("client-id"),
93+
IssuerUrl: common.String("issuer-url"),
94+
},
95+
},
96+
},
97+
},
98+
expectErr: false,
99+
},
100+
{
101+
name: "OpenIdConnectAuthEnabledWithInvalidClusterType",
102+
c: &OCIManagedControlPlane{
103+
Spec: OCIManagedControlPlaneSpec{
104+
ClusterType: BasicClusterType,
105+
ClusterOption: ClusterOptions{
106+
OpenIdConnectTokenAuthenticationConfig: &OpenIDConnectTokenAuthenticationConfig{
107+
IsOpenIdConnectAuthEnabled: *common.Bool(true),
108+
ClientId: common.String("client-id"),
109+
IssuerUrl: common.String("issuer-url"),
110+
},
111+
},
112+
},
113+
},
114+
errorMgsShouldContain: "ClusterType needs to be set to ENHANCED_CLUSTER for OpenIdConnectTokenAuthenticationConfig to be enabled.",
115+
expectErr: true,
116+
},
117+
{
118+
name: "OpenIdConnectAuthEnabledWithMissingClientId",
119+
c: &OCIManagedControlPlane{
120+
Spec: OCIManagedControlPlaneSpec{
121+
ClusterType: EnhancedClusterType,
122+
ClusterOption: ClusterOptions{
123+
OpenIdConnectTokenAuthenticationConfig: &OpenIDConnectTokenAuthenticationConfig{
124+
IsOpenIdConnectAuthEnabled: *common.Bool(true),
125+
IssuerUrl: common.String("issuer-url"),
126+
},
127+
},
128+
},
129+
},
130+
errorMgsShouldContain: "ClientId cannot be empty when OpenIdConnectAuth is enabled.",
131+
expectErr: true,
132+
},
133+
{
134+
name: "OpenIdConnectAuthEnabledWithMissingIssuerUrl",
135+
c: &OCIManagedControlPlane{
136+
Spec: OCIManagedControlPlaneSpec{
137+
ClusterType: EnhancedClusterType,
138+
ClusterOption: ClusterOptions{
139+
OpenIdConnectTokenAuthenticationConfig: &OpenIDConnectTokenAuthenticationConfig{
140+
IsOpenIdConnectAuthEnabled: *common.Bool(true),
141+
ClientId: common.String("client-id"),
142+
},
143+
},
144+
},
145+
},
146+
errorMgsShouldContain: "IssuerUrl cannot be empty when OpenIdConnectAuth is enabled.",
147+
expectErr: true,
148+
},
149+
{
150+
name: "OpenIdConnectAuthDisabled",
151+
c: &OCIManagedControlPlane{
152+
Spec: OCIManagedControlPlaneSpec{
153+
ClusterType: BasicClusterType,
154+
ClusterOption: ClusterOptions{
155+
OpenIdConnectTokenAuthenticationConfig: &OpenIDConnectTokenAuthenticationConfig{
156+
IsOpenIdConnectAuthEnabled: *common.Bool(false),
157+
},
158+
},
159+
},
160+
},
161+
expectErr: false,
162+
},
82163
}
83164
for _, test := range tests {
84165
t.Run(test.name, func(t *testing.T) {

0 commit comments

Comments
 (0)