Skip to content

Commit 2b32d3d

Browse files
committed
add auditLogRoleARN field to ROSAControlPlane
1 parent 52469b2 commit 2b32d3d

File tree

5 files changed

+203
-131
lines changed

5 files changed

+203
-131
lines changed

config/crd/bases/controlplane.cluster.x-k8s.io_rosacontrolplanes.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ spec:
5353
description: AdditionalTags are user-defined tags to be added on the
5454
AWS resources associated with the control plane.
5555
type: object
56+
auditLogRoleARN:
57+
description: AuditLogRoleARN defines the role that is used to forward
58+
audit logs to AWS CloudWatch. If not set, audit log forwarding is
59+
disabled.
60+
type: string
5661
availabilityZones:
5762
description: AvailabilityZones describe AWS AvailabilityZones of the
5863
worker nodes. should match the AvailabilityZones of the provided
@@ -146,8 +151,8 @@ spec:
146151
- Public
147152
- Private
148153
type: string
149-
etcdEncryptionKMSArn:
150-
description: EtcdEncryptionKMSArn is the ARN of the KMS key used to
154+
etcdEncryptionKMSARN:
155+
description: EtcdEncryptionKMSARN is the ARN of the KMS key used to
151156
encrypt etcd. The key itself needs to be created out-of-band by
152157
the user and tagged with `red-hat:true`.
153158
type: string

controlplane/rosa/api/v1beta2/rosacontrolplane_types.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,15 @@ type RosaControlPlaneSpec struct { //nolint: maligned
129129
// +optional
130130
AdditionalTags infrav1.Tags `json:"additionalTags,omitempty"`
131131

132-
// EtcdEncryptionKMSArn is the ARN of the KMS key used to encrypt etcd. The key itself needs to be
132+
// EtcdEncryptionKMSARN is the ARN of the KMS key used to encrypt etcd. The key itself needs to be
133133
// created out-of-band by the user and tagged with `red-hat:true`.
134134
// +optional
135-
EtcdEncryptionKMSArn string `json:"etcdEncryptionKMSArn,omitempty"`
135+
EtcdEncryptionKMSARN string `json:"etcdEncryptionKMSARN,omitempty"`
136+
137+
// AuditLogRoleARN defines the role that is used to forward audit logs to AWS CloudWatch.
138+
// If not set, audit log forwarding is disabled.
139+
// +optional
140+
AuditLogRoleARN string `json:"auditLogRoleARN,omitempty"`
136141

137142
// CredentialsSecretRef references a secret with necessary credentials to connect to the OCM API.
138143
// The secret should contain the following data keys:

controlplane/rosa/api/v1beta2/rosacontrolplane_webhook.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ func (r *ROSAControlPlane) validateNetwork() field.ErrorList {
125125
}
126126

127127
func (r *ROSAControlPlane) validateEtcdEncryptionKMSArn() *field.Error {
128-
err := kmsArnRegexpValidator.ValidateKMSKeyARN(&r.Spec.EtcdEncryptionKMSArn)
128+
err := kmsArnRegexpValidator.ValidateKMSKeyARN(&r.Spec.EtcdEncryptionKMSARN)
129129
if err != nil {
130-
return field.Invalid(field.NewPath("spec.EtcdEncryptionKMSArn"), r.Spec.EtcdEncryptionKMSArn, err.Error())
130+
return field.Invalid(field.NewPath("spec.etcdEncryptionKMSARN"), r.Spec.EtcdEncryptionKMSARN, err.Error())
131131
}
132132

133133
return nil

controlplane/rosa/controllers/rosacontrolplane_controller.go

Lines changed: 157 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,16 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
241241
}
242242
rosaScope.ControlPlane.Spec.ControlPlaneEndpoint = *apiEndpoint
243243

244-
if err := r.reconcileKubeconfig(ctx, rosaScope, ocmClient, cluster); err != nil {
245-
return ctrl.Result{}, fmt.Errorf("failed to reconcile kubeconfig: %w", err)
244+
if err := r.updateOCMCluster(rosaScope, ocmClient, cluster, creator); err != nil {
245+
return ctrl.Result{}, fmt.Errorf("failed to update rosa control plane: %w", err)
246246
}
247247
if err := r.reconcileClusterVersion(rosaScope, ocmClient, cluster); err != nil {
248248
return ctrl.Result{}, err
249249
}
250+
if err := r.reconcileKubeconfig(ctx, rosaScope, ocmClient, cluster); err != nil {
251+
return ctrl.Result{}, fmt.Errorf("failed to reconcile kubeconfig: %w", err)
252+
}
253+
250254
return ctrl.Result{}, nil
251255
case cmv1.ClusterStateError:
252256
errorMessage := cluster.Status().ProvisionErrorMessage()
@@ -272,80 +276,9 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
272276
return ctrl.Result{RequeueAfter: time.Second * 60}, nil
273277
}
274278

275-
billingAccount := *rosaScope.Identity.Account
276-
if rosaScope.ControlPlane.Spec.BillingAccount != "" {
277-
billingAccount = rosaScope.ControlPlane.Spec.BillingAccount
278-
}
279-
280-
ocmClusterSpec := ocm.Spec{
281-
DryRun: ptr.To(false),
282-
Name: rosaScope.RosaClusterName(),
283-
DomainPrefix: rosaScope.ControlPlane.Spec.DomainPrefix,
284-
Region: rosaScope.ControlPlane.Spec.Region,
285-
MultiAZ: true,
286-
Version: ocm.CreateVersionID(rosaScope.ControlPlane.Spec.Version, ocm.DefaultChannelGroup),
287-
ChannelGroup: ocm.DefaultChannelGroup,
288-
DisableWorkloadMonitoring: ptr.To(true),
289-
DefaultIngress: ocm.NewDefaultIngressSpec(), // n.b. this is a no-op when it's set to the default value
290-
ComputeMachineType: rosaScope.ControlPlane.Spec.DefaultMachinePoolSpec.InstanceType,
291-
AvailabilityZones: rosaScope.ControlPlane.Spec.AvailabilityZones,
292-
Tags: rosaScope.ControlPlane.Spec.AdditionalTags,
293-
EtcdEncryption: rosaScope.ControlPlane.Spec.EtcdEncryptionKMSArn != "",
294-
EtcdEncryptionKMSArn: rosaScope.ControlPlane.Spec.EtcdEncryptionKMSArn,
295-
296-
SubnetIds: rosaScope.ControlPlane.Spec.Subnets,
297-
IsSTS: true,
298-
RoleARN: rosaScope.ControlPlane.Spec.InstallerRoleARN,
299-
SupportRoleARN: rosaScope.ControlPlane.Spec.SupportRoleARN,
300-
WorkerRoleARN: rosaScope.ControlPlane.Spec.WorkerRoleARN,
301-
OperatorIAMRoles: operatorIAMRoles(rosaScope.ControlPlane.Spec.RolesRef),
302-
OidcConfigId: rosaScope.ControlPlane.Spec.OIDCID,
303-
Mode: "auto",
304-
Hypershift: ocm.Hypershift{
305-
Enabled: true,
306-
},
307-
BillingAccount: billingAccount,
308-
AWSCreator: creator,
309-
}
310-
311-
if rosaScope.ControlPlane.Spec.EndpointAccess == rosacontrolplanev1.Private {
312-
ocmClusterSpec.Private = ptr.To(true)
313-
ocmClusterSpec.PrivateLink = ptr.To(true)
314-
}
315-
316-
if networkSpec := rosaScope.ControlPlane.Spec.Network; networkSpec != nil {
317-
if networkSpec.MachineCIDR != "" {
318-
_, machineCIDR, err := net.ParseCIDR(networkSpec.MachineCIDR)
319-
if err != nil {
320-
return ctrl.Result{}, err
321-
}
322-
ocmClusterSpec.MachineCIDR = *machineCIDR
323-
}
324-
325-
if networkSpec.PodCIDR != "" {
326-
_, podCIDR, err := net.ParseCIDR(networkSpec.PodCIDR)
327-
if err != nil {
328-
return ctrl.Result{}, err
329-
}
330-
ocmClusterSpec.PodCIDR = *podCIDR
331-
}
332-
333-
if networkSpec.ServiceCIDR != "" {
334-
_, serviceCIDR, err := net.ParseCIDR(networkSpec.ServiceCIDR)
335-
if err != nil {
336-
return ctrl.Result{}, err
337-
}
338-
ocmClusterSpec.ServiceCIDR = *serviceCIDR
339-
}
340-
341-
ocmClusterSpec.HostPrefix = networkSpec.HostPrefix
342-
ocmClusterSpec.NetworkType = networkSpec.NetworkType
343-
}
344-
345-
// Set cluster compute autoscaling replicas
346-
if computeAutoscaling := rosaScope.ControlPlane.Spec.DefaultMachinePoolSpec.Autoscaling; computeAutoscaling != nil {
347-
ocmClusterSpec.MaxReplicas = computeAutoscaling.MaxReplicas
348-
ocmClusterSpec.MinReplicas = computeAutoscaling.MinReplicas
279+
ocmClusterSpec, err := buildOCMClusterSpec(rosaScope.ControlPlane.Spec, creator)
280+
if err != nil {
281+
return ctrl.Result{}, err
349282
}
350283

351284
cluster, err = ocmClient.CreateCluster(ocmClusterSpec)
@@ -364,51 +297,6 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
364297
return ctrl.Result{}, nil
365298
}
366299

367-
func operatorIAMRoles(rolesRef rosacontrolplanev1.AWSRolesRef) []ocm.OperatorIAMRole {
368-
return []ocm.OperatorIAMRole{
369-
{
370-
Name: "cloud-credentials",
371-
Namespace: "openshift-ingress-operator",
372-
RoleARN: rolesRef.IngressARN,
373-
},
374-
{
375-
Name: "installer-cloud-credentials",
376-
Namespace: "openshift-image-registry",
377-
RoleARN: rolesRef.ImageRegistryARN,
378-
},
379-
{
380-
Name: "ebs-cloud-credentials",
381-
Namespace: "openshift-cluster-csi-drivers",
382-
RoleARN: rolesRef.StorageARN,
383-
},
384-
{
385-
Name: "cloud-credentials",
386-
Namespace: "openshift-cloud-network-config-controller",
387-
RoleARN: rolesRef.NetworkARN,
388-
},
389-
{
390-
Name: "kube-controller-manager",
391-
Namespace: "kube-system",
392-
RoleARN: rolesRef.KubeCloudControllerARN,
393-
},
394-
{
395-
Name: "kms-provider",
396-
Namespace: "kube-system",
397-
RoleARN: rolesRef.KMSProviderARN,
398-
},
399-
{
400-
Name: "control-plane-operator",
401-
Namespace: "kube-system",
402-
RoleARN: rolesRef.ControlPlaneOperatorARN,
403-
},
404-
{
405-
Name: "capa-controller-manager",
406-
Namespace: "kube-system",
407-
RoleARN: rolesRef.NodePoolManagementARN,
408-
},
409-
}
410-
}
411-
412300
func (r *ROSAControlPlaneReconciler) reconcileDelete(ctx context.Context, rosaScope *scope.ROSAControlPlaneScope) (res ctrl.Result, reterr error) {
413301
rosaScope.Info("Reconciling ROSAControlPlane delete")
414302

@@ -497,6 +385,29 @@ func (r *ROSAControlPlaneReconciler) reconcileClusterVersion(rosaScope *scope.RO
497385
return nil
498386
}
499387

388+
func (r *ROSAControlPlaneReconciler) updateOCMCluster(rosaScope *scope.ROSAControlPlaneScope, ocmClient *ocm.Client, cluster *cmv1.Cluster, creator *rosaaws.Creator) error {
389+
currentAuditLogRole := cluster.AWS().AuditLog().RoleArn()
390+
if currentAuditLogRole == rosaScope.ControlPlane.Spec.AuditLogRoleARN {
391+
return nil
392+
}
393+
394+
ocmClusterSpec := ocm.Spec{
395+
AuditLogRoleARN: ptr.To(rosaScope.ControlPlane.Spec.AuditLogRoleARN),
396+
}
397+
398+
// if this fails, the provided role is likely invalid or it doesn't have the required permissions.
399+
if err := ocmClient.UpdateCluster(cluster.ID(), creator, ocmClusterSpec); err != nil {
400+
conditions.MarkFalse(rosaScope.ControlPlane,
401+
rosacontrolplanev1.ROSAControlPlaneValidCondition,
402+
rosacontrolplanev1.ROSAControlPlaneInvalidConfigurationReason,
403+
clusterv1.ConditionSeverityError,
404+
err.Error())
405+
return err
406+
}
407+
408+
return nil
409+
}
410+
500411
func (r *ROSAControlPlaneReconciler) reconcileKubeconfig(ctx context.Context, rosaScope *scope.ROSAControlPlaneScope, ocmClient *ocm.Client, cluster *cmv1.Cluster) error {
501412
rosaScope.Debug("Reconciling ROSA kubeconfig for cluster", "cluster-name", rosaScope.RosaClusterName())
502413

@@ -627,6 +538,131 @@ func validateControlPlaneSpec(ocmClient *ocm.Client, rosaScope *scope.ROSAContro
627538
return "", nil
628539
}
629540

541+
func buildOCMClusterSpec(controPlaneSpec rosacontrolplanev1.RosaControlPlaneSpec, creator *rosaaws.Creator) (ocm.Spec, error) {
542+
billingAccount := controPlaneSpec.BillingAccount
543+
if billingAccount == "" {
544+
billingAccount = creator.AccountID
545+
}
546+
547+
ocmClusterSpec := ocm.Spec{
548+
DryRun: ptr.To(false),
549+
Name: controPlaneSpec.RosaClusterName,
550+
Region: controPlaneSpec.Region,
551+
MultiAZ: true,
552+
Version: ocm.CreateVersionID(controPlaneSpec.Version, ocm.DefaultChannelGroup),
553+
ChannelGroup: ocm.DefaultChannelGroup,
554+
DisableWorkloadMonitoring: ptr.To(true),
555+
DefaultIngress: ocm.NewDefaultIngressSpec(), // n.b. this is a no-op when it's set to the default value
556+
ComputeMachineType: controPlaneSpec.DefaultMachinePoolSpec.InstanceType,
557+
AvailabilityZones: controPlaneSpec.AvailabilityZones,
558+
Tags: controPlaneSpec.AdditionalTags,
559+
EtcdEncryption: controPlaneSpec.EtcdEncryptionKMSARN != "",
560+
EtcdEncryptionKMSArn: controPlaneSpec.EtcdEncryptionKMSARN,
561+
562+
SubnetIds: controPlaneSpec.Subnets,
563+
IsSTS: true,
564+
RoleARN: controPlaneSpec.InstallerRoleARN,
565+
SupportRoleARN: controPlaneSpec.SupportRoleARN,
566+
WorkerRoleARN: controPlaneSpec.WorkerRoleARN,
567+
OperatorIAMRoles: operatorIAMRoles(controPlaneSpec.RolesRef),
568+
OidcConfigId: controPlaneSpec.OIDCID,
569+
Mode: "auto",
570+
Hypershift: ocm.Hypershift{
571+
Enabled: true,
572+
},
573+
BillingAccount: billingAccount,
574+
AWSCreator: creator,
575+
AuditLogRoleARN: ptr.To(controPlaneSpec.AuditLogRoleARN),
576+
}
577+
578+
if controPlaneSpec.EndpointAccess == rosacontrolplanev1.Private {
579+
ocmClusterSpec.Private = ptr.To(true)
580+
ocmClusterSpec.PrivateLink = ptr.To(true)
581+
}
582+
583+
if networkSpec := controPlaneSpec.Network; networkSpec != nil {
584+
if networkSpec.MachineCIDR != "" {
585+
_, machineCIDR, err := net.ParseCIDR(networkSpec.MachineCIDR)
586+
if err != nil {
587+
return ocmClusterSpec, err
588+
}
589+
ocmClusterSpec.MachineCIDR = *machineCIDR
590+
}
591+
592+
if networkSpec.PodCIDR != "" {
593+
_, podCIDR, err := net.ParseCIDR(networkSpec.PodCIDR)
594+
if err != nil {
595+
return ocmClusterSpec, err
596+
}
597+
ocmClusterSpec.PodCIDR = *podCIDR
598+
}
599+
600+
if networkSpec.ServiceCIDR != "" {
601+
_, serviceCIDR, err := net.ParseCIDR(networkSpec.ServiceCIDR)
602+
if err != nil {
603+
return ocmClusterSpec, err
604+
}
605+
ocmClusterSpec.ServiceCIDR = *serviceCIDR
606+
}
607+
608+
ocmClusterSpec.HostPrefix = networkSpec.HostPrefix
609+
ocmClusterSpec.NetworkType = networkSpec.NetworkType
610+
}
611+
612+
// Set cluster compute autoscaling replicas
613+
if computeAutoscaling := controPlaneSpec.DefaultMachinePoolSpec.Autoscaling; computeAutoscaling != nil {
614+
ocmClusterSpec.MaxReplicas = computeAutoscaling.MaxReplicas
615+
ocmClusterSpec.MinReplicas = computeAutoscaling.MinReplicas
616+
}
617+
618+
return ocmClusterSpec, nil
619+
}
620+
621+
func operatorIAMRoles(rolesRef rosacontrolplanev1.AWSRolesRef) []ocm.OperatorIAMRole {
622+
return []ocm.OperatorIAMRole{
623+
{
624+
Name: "cloud-credentials",
625+
Namespace: "openshift-ingress-operator",
626+
RoleARN: rolesRef.IngressARN,
627+
},
628+
{
629+
Name: "installer-cloud-credentials",
630+
Namespace: "openshift-image-registry",
631+
RoleARN: rolesRef.ImageRegistryARN,
632+
},
633+
{
634+
Name: "ebs-cloud-credentials",
635+
Namespace: "openshift-cluster-csi-drivers",
636+
RoleARN: rolesRef.StorageARN,
637+
},
638+
{
639+
Name: "cloud-credentials",
640+
Namespace: "openshift-cloud-network-config-controller",
641+
RoleARN: rolesRef.NetworkARN,
642+
},
643+
{
644+
Name: "kube-controller-manager",
645+
Namespace: "kube-system",
646+
RoleARN: rolesRef.KubeCloudControllerARN,
647+
},
648+
{
649+
Name: "kms-provider",
650+
Namespace: "kube-system",
651+
RoleARN: rolesRef.KMSProviderARN,
652+
},
653+
{
654+
Name: "control-plane-operator",
655+
Namespace: "kube-system",
656+
RoleARN: rolesRef.ControlPlaneOperatorARN,
657+
},
658+
{
659+
Name: "capa-controller-manager",
660+
Namespace: "kube-system",
661+
RoleARN: rolesRef.NodePoolManagementARN,
662+
},
663+
}
664+
}
665+
630666
func (r *ROSAControlPlaneReconciler) rosaClusterToROSAControlPlane(log *logger.Logger) handler.MapFunc {
631667
return func(ctx context.Context, o client.Object) []ctrl.Request {
632668
rosaCluster, ok := o.(*expinfrav1.ROSACluster)

0 commit comments

Comments
 (0)