Skip to content

Commit bc4ddf2

Browse files
committed
feat: add support for OCM role creation
1 parent e172382 commit bc4ddf2

12 files changed

Lines changed: 1538 additions & 12 deletions
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.19.0
7+
name: ocmroleconfigs.infrastructure.cluster.x-k8s.io
8+
spec:
9+
group: infrastructure.cluster.x-k8s.io
10+
names:
11+
categories:
12+
- cluster-api
13+
kind: OCMRoleConfig
14+
listKind: OCMRoleConfigList
15+
plural: ocmroleconfigs
16+
shortNames:
17+
- ocmrole
18+
singular: ocmroleconfig
19+
scope: Cluster
20+
versions:
21+
- name: v1beta2
22+
schema:
23+
openAPIV3Schema:
24+
description: OCMRoleConfig is the Schema for the ocmroleconfigs API
25+
properties:
26+
apiVersion:
27+
description: |-
28+
APIVersion defines the versioned schema of this representation of an object.
29+
Servers should convert recognized schemas to the latest internal value, and
30+
may reject unrecognized values.
31+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
32+
type: string
33+
kind:
34+
description: |-
35+
Kind is a string value representing the REST resource this object represents.
36+
Servers may infer this from the endpoint the client submits requests to.
37+
Cannot be updated.
38+
In CamelCase.
39+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
40+
type: string
41+
metadata:
42+
type: object
43+
spec:
44+
description: OCMRoleConfigSpec defines the desired state of OCMRoleConfig
45+
properties:
46+
credentialsSecretRef:
47+
description: CredentialsSecretRef references a secret with necessary
48+
credentials to connect to the OCM API.
49+
properties:
50+
name:
51+
default: ""
52+
description: |-
53+
Name of the referent.
54+
This field is effectively required, but due to backwards compatibility is
55+
allowed to be empty. Instances of this type with an empty value here are
56+
almost certainly wrong.
57+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
58+
type: string
59+
type: object
60+
x-kubernetes-map-type: atomic
61+
identityRef:
62+
description: |-
63+
IdentityRef is a reference to an identity to be used when reconciling the OCM Role Config.
64+
If no identity is specified, the default identity for this controller will be used.
65+
properties:
66+
kind:
67+
description: Kind of the identity.
68+
enum:
69+
- AWSClusterControllerIdentity
70+
- AWSClusterRoleIdentity
71+
- AWSClusterStaticIdentity
72+
type: string
73+
name:
74+
description: Name of the identity.
75+
minLength: 1
76+
type: string
77+
required:
78+
- kind
79+
- name
80+
type: object
81+
managedPolicies:
82+
default: false
83+
description: ManagedPolicies indicates whether to use AWS-managed
84+
policies (true) or customer-managed policies (false).
85+
type: boolean
86+
path:
87+
default: /
88+
description: Path is the IAM path for the OCM role.
89+
type: string
90+
permissionsBoundaryARN:
91+
description: PermissionsBoundaryARN is the ARN of the policy that
92+
is used to set the permissions boundary for the OCM role.
93+
type: string
94+
profile:
95+
default: Standard
96+
description: Profile defines the permission level for the OCM role.
97+
enum:
98+
- Standard
99+
- Admin
100+
- NoConsole
101+
type: string
102+
x-kubernetes-validations:
103+
- message: profile is immutable
104+
rule: self == oldSelf
105+
rolePrefix:
106+
description: |-
107+
RolePrefix is the user-defined prefix for the OCM role name.
108+
The final role name will be: {RolePrefix}-OCM-Role-{ExternalID}
109+
where ExternalID is the organization's external identifier from OCM.
110+
maxLength: 32
111+
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
112+
type: string
113+
x-kubernetes-validations:
114+
- message: rolePrefix is immutable
115+
rule: self == oldSelf
116+
required:
117+
- profile
118+
- rolePrefix
119+
type: object
120+
status:
121+
description: OCMRoleConfigStatus defines the observed state of OCMRoleConfig
122+
properties:
123+
conditions:
124+
description: Conditions specifies the OCMRoleConfig conditions
125+
items:
126+
description: Condition defines an observation of a Cluster API resource
127+
operational state.
128+
properties:
129+
lastTransitionTime:
130+
description: |-
131+
lastTransitionTime is the last time the condition transitioned from one status to another.
132+
This should be when the underlying condition changed. If that is not known, then using the time when
133+
the API field changed is acceptable.
134+
format: date-time
135+
type: string
136+
message:
137+
description: |-
138+
message is a human readable message indicating details about the transition.
139+
This field may be empty.
140+
maxLength: 10240
141+
minLength: 1
142+
type: string
143+
reason:
144+
description: |-
145+
reason is the reason for the condition's last transition in CamelCase.
146+
The specific API may choose whether or not this field is considered a guaranteed API.
147+
This field may be empty.
148+
maxLength: 256
149+
minLength: 1
150+
type: string
151+
severity:
152+
description: |-
153+
severity provides an explicit classification of Reason code, so the users or machines can immediately
154+
understand the current situation and act accordingly.
155+
The Severity field MUST be set only when Status=False.
156+
maxLength: 32
157+
type: string
158+
status:
159+
description: status of the condition, one of True, False, Unknown.
160+
type: string
161+
type:
162+
description: |-
163+
type of condition in CamelCase or in foo.example.com/CamelCase.
164+
Many .condition.type values are consistent across resources like Available, but because arbitrary conditions
165+
can be useful (see .node.status.conditions), the ability to deconflict is important.
166+
maxLength: 256
167+
minLength: 1
168+
type: string
169+
required:
170+
- lastTransitionTime
171+
- status
172+
- type
173+
type: object
174+
type: array
175+
linked:
176+
description: Linked indicates whether the role has been successfully
177+
linked to the OCM organization.
178+
type: boolean
179+
organizationID:
180+
description: OrganizationID is the OCM organization ID that this role
181+
is linked to.
182+
type: string
183+
roleARN:
184+
description: RoleARN is the ARN of the created OCM role.
185+
type: string
186+
type: object
187+
type: object
188+
served: true
189+
storage: true
190+
subresources:
191+
status: {}

config/rbac/role.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ rules:
198198
- awsclusters/status
199199
- awsfargateprofiles/status
200200
- awsmachinetemplates/status
201+
- ocmroleconfigs/status
201202
- rosaclusters/status
202203
- rosanetworks/status
203204
- rosaroleconfigs/status
@@ -229,6 +230,7 @@ rules:
229230
- infrastructure.cluster.x-k8s.io
230231
resources:
231232
- awsmachines
233+
- ocmroleconfigs
232234
- rosamachinepools
233235
- rosanetworks
234236
- rosaroleconfigs
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
Copyright 2026 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta2
18+
19+
import (
20+
corev1 "k8s.io/api/core/v1"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
23+
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
24+
clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
25+
)
26+
27+
// OCMRoleProfile defines the permission level for the OCM role
28+
type OCMRoleProfile string
29+
30+
const (
31+
// OCMRoleProfileStandard provides standard OCM permissions
32+
OCMRoleProfileStandard OCMRoleProfile = "Standard"
33+
34+
// OCMRoleProfileAdmin provides admin OCM permissions
35+
OCMRoleProfileAdmin OCMRoleProfile = "Admin"
36+
37+
// OCMRoleProfileNoConsole provides minimal OCM permissions (cannot use console.redhat.com)
38+
OCMRoleProfileNoConsole OCMRoleProfile = "NoConsole"
39+
)
40+
41+
const (
42+
// OCMRoleConfigReadyCondition condition reports on the successful reconciliation of OCMRoleConfig.
43+
OCMRoleConfigReadyCondition = "OCMRoleConfigReady"
44+
45+
// OCMRoleConfigDeletionFailedReason used to report failures while deleting OCMRoleConfig.
46+
OCMRoleConfigDeletionFailedReason = "DeletionFailed"
47+
48+
// OCMRoleConfigReconciliationFailedReason used to report reconciliation failures.
49+
OCMRoleConfigReconciliationFailedReason = "ReconciliationFailed"
50+
51+
// OCMRoleConfigDeletionStarted used to indicate that the deletion of OCMRoleConfig has started.
52+
OCMRoleConfigDeletionStarted = "DeletionStarted"
53+
54+
// OCMRoleConfigCreatedReason used to indicate that the OCMRoleConfig has been created.
55+
OCMRoleConfigCreatedReason = "Created"
56+
57+
// OCMRoleConfigLinkedReason used to indicate that the OCM role has been linked to the organization.
58+
OCMRoleConfigLinkedReason = "Linked"
59+
)
60+
61+
// OCMRoleConfigSpec defines the desired state of OCMRoleConfig
62+
type OCMRoleConfigSpec struct {
63+
// RolePrefix is the user-defined prefix for the OCM role name.
64+
// The final role name will be: {RolePrefix}-OCM-Role-{ExternalID}
65+
// where ExternalID is the organization's external identifier from OCM.
66+
// +kubebuilder:validation:Required
67+
// +kubebuilder:validation:MaxLength:=32
68+
// +kubebuilder:validation:Pattern:=`^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$`
69+
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="rolePrefix is immutable"
70+
RolePrefix string `json:"rolePrefix"`
71+
72+
// Profile defines the permission level for the OCM role.
73+
// +kubebuilder:validation:Enum=Standard;Admin;NoConsole
74+
// +kubebuilder:default=Standard
75+
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="profile is immutable"
76+
Profile OCMRoleProfile `json:"profile"`
77+
78+
// PermissionsBoundaryARN is the ARN of the policy that is used to set the permissions boundary for the OCM role.
79+
// +optional
80+
PermissionsBoundaryARN string `json:"permissionsBoundaryARN,omitempty"`
81+
82+
// Path is the IAM path for the OCM role.
83+
// +optional
84+
// +kubebuilder:default="/"
85+
Path string `json:"path,omitempty"`
86+
87+
// ManagedPolicies indicates whether to use AWS-managed policies (true) or customer-managed policies (false).
88+
// +optional
89+
// +kubebuilder:default=false
90+
ManagedPolicies bool `json:"managedPolicies,omitempty"`
91+
92+
// IdentityRef is a reference to an identity to be used when reconciling the OCM Role Config.
93+
// If no identity is specified, the default identity for this controller will be used.
94+
// +optional
95+
IdentityRef *infrav1.AWSIdentityReference `json:"identityRef,omitempty"`
96+
97+
// CredentialsSecretRef references a secret with necessary credentials to connect to the OCM API.
98+
// +optional
99+
CredentialsSecretRef *corev1.LocalObjectReference `json:"credentialsSecretRef,omitempty"`
100+
}
101+
102+
// OCMRoleConfigStatus defines the observed state of OCMRoleConfig
103+
type OCMRoleConfigStatus struct {
104+
// RoleARN is the ARN of the created OCM role.
105+
RoleARN string `json:"roleARN,omitempty"`
106+
107+
// OrganizationID is the OCM organization ID that this role is linked to.
108+
OrganizationID string `json:"organizationID,omitempty"`
109+
110+
// Linked indicates whether the role has been successfully linked to the OCM organization.
111+
Linked bool `json:"linked,omitempty"`
112+
113+
// Conditions specifies the OCMRoleConfig conditions
114+
Conditions clusterv1beta1.Conditions `json:"conditions,omitempty"`
115+
}
116+
117+
// OCMRoleConfig is the Schema for the ocmroleconfigs API
118+
// +kubebuilder:object:root=true
119+
// +kubebuilder:resource:path=ocmroleconfigs,scope=Cluster,categories=cluster-api,shortName=ocmrole
120+
// +kubebuilder:storageversion
121+
// +kubebuilder:subresource:status
122+
type OCMRoleConfig struct {
123+
metav1.TypeMeta `json:",inline"`
124+
metav1.ObjectMeta `json:"metadata,omitempty"`
125+
126+
Spec OCMRoleConfigSpec `json:"spec,omitempty"`
127+
Status OCMRoleConfigStatus `json:"status,omitempty"`
128+
}
129+
130+
// OCMRoleConfigList contains a list of OCMRoleConfig
131+
// +kubebuilder:object:root=true
132+
type OCMRoleConfigList struct {
133+
metav1.TypeMeta `json:",inline"`
134+
metav1.ListMeta `json:"metadata,omitempty"`
135+
Items []OCMRoleConfig `json:"items"`
136+
}
137+
138+
// SetConditions sets the conditions of the OCMRoleConfig.
139+
func (r *OCMRoleConfig) SetConditions(conditions clusterv1beta1.Conditions) {
140+
r.Status.Conditions = conditions
141+
}
142+
143+
// GetConditions returns the observations of the operational state of the OCMRoleConfig resource.
144+
func (r *OCMRoleConfig) GetConditions() clusterv1beta1.Conditions {
145+
return r.Status.Conditions
146+
}
147+
148+
func init() {
149+
SchemeBuilder.Register(&OCMRoleConfig{}, &OCMRoleConfigList{})
150+
}

0 commit comments

Comments
 (0)