From 02c159609adf7d236b382478b9fa4879f5a12301 Mon Sep 17 00:00:00 2001 From: Helder Santana Date: Wed, 8 Jan 2025 16:40:03 -0300 Subject: [PATCH] IP Access List CRD --- PROJECT | 13 ++ api/v1/atlasipaccesslist_types.go | 110 ++++++++++ api/v1/atlasipaccesslist_types_test.go | 172 ++++++++++++++++ api/v1/status/atlasipaccesslist.go | 72 +++++++ api/v1/status/zz_generated.deepcopy.go | 36 ++++ api/v1/zz_generated.deepcopy.go | 101 +++++++++ .../atlas.mongodb.com_atlasipaccesslists.yaml | 192 ++++++++++++++++++ config/crd/kustomization.yaml | 1 + .../rbac/atlasipaccesslist_editor_role.yaml | 27 +++ .../rbac/atlasipaccesslist_viewer_role.yaml | 23 +++ config/rbac/kustomization.yaml | 2 + .../samples/atlas_v1_atlasipaccesslist.yaml | 18 ++ config/samples/kustomization.yaml | 1 + 13 files changed, 768 insertions(+) create mode 100644 api/v1/atlasipaccesslist_types.go create mode 100644 api/v1/atlasipaccesslist_types_test.go create mode 100644 api/v1/status/atlasipaccesslist.go create mode 100644 config/crd/bases/atlas.mongodb.com_atlasipaccesslists.yaml create mode 100644 config/rbac/atlasipaccesslist_editor_role.yaml create mode 100644 config/rbac/atlasipaccesslist_viewer_role.yaml create mode 100644 config/samples/atlas_v1_atlasipaccesslist.yaml diff --git a/PROJECT b/PROJECT index 79d599ceff..994554d2ac 100644 --- a/PROJECT +++ b/PROJECT @@ -1,3 +1,7 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: mongodb.com layout: - go.kubebuilder.io/v4 @@ -113,4 +117,13 @@ resources: kind: AtlasCustomRole path: github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1 version: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: mongodb.com + group: atlas + kind: AtlasIPAccessList + path: github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1 + version: v1 version: "3" diff --git a/api/v1/atlasipaccesslist_types.go b/api/v1/atlasipaccesslist_types.go new file mode 100644 index 0000000000..d2a9a78cca --- /dev/null +++ b/api/v1/atlasipaccesslist_types.go @@ -0,0 +1,110 @@ +/* +Copyright 2025 MongoDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status" +) + +func init() { + SchemeBuilder.Register(&AtlasIPAccessList{}, &AtlasIPAccessListList{}) +} + +// +kubebuilder:validation:XValidation:rule="(has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef) && has(self.projectRef))",message="must define only one project reference through externalProjectRef or projectRef" +// +kubebuilder:validation:XValidation:rule="(has(self.externalProjectRef) && has(self.connectionSecret)) || !has(self.externalProjectRef)",message="must define a local connection secret when referencing an external project" + +// AtlasIPAccessListSpec defines the desired state of AtlasIPAccessList. +type AtlasIPAccessListSpec struct { + // ProjectReference is the dual external or kubernetes reference with access credentials + ProjectDualReference `json:",inline"` + // Entries is the list of IP Access to be managed + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + Entries []IPAccessEntry `json:"entries"` +} + +// +kubebuilder:validation:XValidation:rule="!(has(self.ipAddress) && (has(self.cidrBlock) || has(self.awsSecurityGroup))) && !(has(self.cidrBlock) && has(self.awsSecurityGroup))",message="Only one of ipAddress, cidrBlock, or awsSecurityGroup may be set." + +type IPAccessEntry struct { + // Entry using an IP address in this access list entry. + // +optional + IPAddress string `json:"ipAddress,omitempty"` + // Range of IP addresses in CIDR notation in this access list entry. + // +optional + CIDRBlock string `json:"cidrBlock,omitempty"` + // Unique identifier of AWS security group in this access list entry. + // +optional + AwsSecurityGroup string `json:"awsSecurityGroup,omitempty"` + // Date and time after which Atlas deletes the temporary access list entry. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Format=date-time + // +optional + DeleteAfterDate *metav1.Time `json:"deleteAfterDate,omitempty"` + // Comment associated with this access list entry. + // +optional + Comment string `json:"comment,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +groupName:=atlas.mongodb.com +// +kubebuilder:resource:categories=atlas,shortName=aial +// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status` + +// AtlasIPAccessList is the Schema for the atlasipaccesslists API. +type AtlasIPAccessList struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AtlasIPAccessListSpec `json:"spec,omitempty"` + Status status.AtlasIPAccessListStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// AtlasIPAccessListList contains a list of AtlasIPAccessList. +type AtlasIPAccessListList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AtlasIPAccessList `json:"items"` +} + +func (ial *AtlasIPAccessList) Credentials() *api.LocalObjectReference { + return ial.Spec.ConnectionSecret +} + +func (ial *AtlasIPAccessList) ProjectDualRef() *ProjectDualReference { + return &ial.Spec.ProjectDualReference +} + +func (ial *AtlasIPAccessList) GetStatus() api.Status { + return ial.Status +} + +func (ial *AtlasIPAccessList) UpdateStatus(conditions []api.Condition, options ...api.Option) { + ial.Status.Conditions = conditions + ial.Status.ObservedGeneration = ial.ObjectMeta.Generation + + for _, o := range options { + v := o.(status.AtlasIPAccessListStatusOption) + v(&ial.Status) + } +} diff --git a/api/v1/atlasipaccesslist_types_test.go b/api/v1/atlasipaccesslist_types_test.go new file mode 100644 index 0000000000..07558a8954 --- /dev/null +++ b/api/v1/atlasipaccesslist_types_test.go @@ -0,0 +1,172 @@ +/* +Copyright 2025 MongoDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/common" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/cel" +) + +func TestIPAccessListProjectRefCELValidations(t *testing.T) { + launchProjectRefCELTests( + t, + func(pdr *ProjectDualReference) AtlasCustomResource { + pe := AtlasIPAccessList{} + if pdr != nil { + setDualRef(pe.ProjectDualRef(), pdr) + } + return &pe + }, + "../../config/crd/bases/atlas.mongodb.com_atlasipaccesslists.yaml", + ) +} + +func TestEntryUniqueness(t *testing.T) { + testCases := map[string]struct { + obj AtlasCustomResource + expectedErrors []string + }{ + "should fail if IP and CIDR are set in the same entry": { + obj: &AtlasIPAccessList{ + Spec: AtlasIPAccessListSpec{ + ProjectDualReference: ProjectDualReference{ + ProjectRef: &common.ResourceRefNamespaced{ + Name: "my-project", + }, + }, + Entries: []IPAccessEntry{ + { + IPAddress: "10.0.0.1", + CIDRBlock: "192.168.0.0/24", + }, + }, + }, + }, + expectedErrors: []string{"spec.entries[0]: Invalid value: \"object\": Only one of ipAddress, cidrBlock, or awsSecurityGroup may be set."}, + }, + "should fail if IP and AWS SG are set in the same entry": { + obj: &AtlasIPAccessList{ + Spec: AtlasIPAccessListSpec{ + ProjectDualReference: ProjectDualReference{ + ProjectRef: &common.ResourceRefNamespaced{ + Name: "my-project", + }, + }, + Entries: []IPAccessEntry{ + { + IPAddress: "10.0.0.1", + AwsSecurityGroup: "sg-123456", + }, + }, + }, + }, + expectedErrors: []string{"spec.entries[0]: Invalid value: \"object\": Only one of ipAddress, cidrBlock, or awsSecurityGroup may be set."}, + }, + "should fail if CIDR and AWS SG are set in the same entry": { + obj: &AtlasIPAccessList{ + Spec: AtlasIPAccessListSpec{ + ProjectDualReference: ProjectDualReference{ + ProjectRef: &common.ResourceRefNamespaced{ + Name: "my-project", + }, + }, + Entries: []IPAccessEntry{ + { + CIDRBlock: "192.168.0.0/24", + AwsSecurityGroup: "sg-123456", + }, + }, + }, + }, + expectedErrors: []string{"spec.entries[0]: Invalid value: \"object\": Only one of ipAddress, cidrBlock, or awsSecurityGroup may be set."}, + }, + "should fail with multiple entries wrongly set": { + obj: &AtlasIPAccessList{ + Spec: AtlasIPAccessListSpec{ + ProjectDualReference: ProjectDualReference{ + ProjectRef: &common.ResourceRefNamespaced{ + Name: "my-project", + }, + }, + Entries: []IPAccessEntry{ + { + IPAddress: "10.0.0.1", + CIDRBlock: "192.168.0.0/24", + }, + { + CIDRBlock: "192.168.1.0/24", + AwsSecurityGroup: "sg-123456", + }, + }, + }, + }, + expectedErrors: []string{ + "spec.entries[0]: Invalid value: \"object\": Only one of ipAddress, cidrBlock, or awsSecurityGroup may be set.", + "spec.entries[1]: Invalid value: \"object\": Only one of ipAddress, cidrBlock, or awsSecurityGroup may be set.", + }, + }, + "should pass when correctly configured": { + obj: &AtlasIPAccessList{ + Spec: AtlasIPAccessListSpec{ + ProjectDualReference: ProjectDualReference{ + ProjectRef: &common.ResourceRefNamespaced{ + Name: "my-project", + }, + }, + Entries: []IPAccessEntry{ + { + IPAddress: "10.0.0.1", + DeleteAfterDate: pointer.MakePtr(metav1.Now()), + }, + { + CIDRBlock: "192.168.0.0/24", + Comment: "My Network", + }, + { + AwsSecurityGroup: "sg-123456", + }, + }, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + unstructuredObject, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.obj) + require.NoError(t, err) + + validator, err := cel.VersionValidatorFromFile(t, "../../config/crd/bases/atlas.mongodb.com_atlasipaccesslists.yaml", "v1") + assert.NoError(t, err) + errs := validator(unstructuredObject, nil) + + require.Equal(t, len(tc.expectedErrors), len(errs)) + + for i, err := range errs { + assert.Equal(t, tc.expectedErrors[i], err.Error()) + } + }) + } +} diff --git a/api/v1/status/atlasipaccesslist.go b/api/v1/status/atlasipaccesslist.go new file mode 100644 index 0000000000..c228c6690c --- /dev/null +++ b/api/v1/status/atlasipaccesslist.go @@ -0,0 +1,72 @@ +/* +Copyright 2024 MongoDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package status + +import ( + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api" +) + +// AtlasIPAccessListStatus is the most recent observed status of the AtlasIPAccessList cluster. Read-only. +type AtlasIPAccessListStatus struct { + api.Common `json:",inline"` + // + // Status is the state of the ip access list + Entries []IPAccessEntryStatus `json:"entries,omitempty"` +} + +type IPAccessEntryStatus struct { + // Entry is the ip access Atlas is managing + Entry string `json:"entry"` + // Status is the correspondent state of the entry + Status string `json:"status"` +} + +// +kubebuilder:object:generate=false + +type AtlasIPAccessListStatusOption func(s *AtlasIPAccessListStatus) + +func AddIPAccessListEntryStatus(entry, entryStatus string) AtlasIPAccessListStatusOption { + return func(s *AtlasIPAccessListStatus) { + for ix, ipEntryStatus := range s.Entries { + if ipEntryStatus.Entry == entry { + s.Entries[ix].Status = entryStatus + + return + } + } + + s.Entries = append( + s.Entries, + IPAccessEntryStatus{ + Entry: entry, + Status: entryStatus, + }, + ) + } +} + +func RemoveIPAccessListEntryStatus(entry string) AtlasIPAccessListStatusOption { + return func(s *AtlasIPAccessListStatus) { + for ix, ipEntryStatus := range s.Entries { + if ipEntryStatus.Entry == entry { + s.Entries = append(s.Entries[:ix], s.Entries[ix+1:]...) + + return + } + } + } +} diff --git a/api/v1/status/zz_generated.deepcopy.go b/api/v1/status/zz_generated.deepcopy.go index a6d680b5e9..21be0ea4df 100644 --- a/api/v1/status/zz_generated.deepcopy.go +++ b/api/v1/status/zz_generated.deepcopy.go @@ -161,6 +161,27 @@ func (in *AtlasFederatedAuthStatus) DeepCopy() *AtlasFederatedAuthStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AtlasIPAccessListStatus) DeepCopyInto(out *AtlasIPAccessListStatus) { + *out = *in + in.Common.DeepCopyInto(&out.Common) + if in.Entries != nil { + in, out := &in.Entries, &out.Entries + *out = make([]IPAccessEntryStatus, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AtlasIPAccessListStatus. +func (in *AtlasIPAccessListStatus) DeepCopy() *AtlasIPAccessListStatus { + if in == nil { + return nil + } + out := new(AtlasIPAccessListStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AtlasNetworkPeer) DeepCopyInto(out *AtlasNetworkPeer) { *out = *in @@ -597,6 +618,21 @@ func (in *GCPForwardingRule) DeepCopy() *GCPForwardingRule { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAccessEntryStatus) DeepCopyInto(out *IPAccessEntryStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAccessEntryStatus. +func (in *IPAccessEntryStatus) DeepCopy() *IPAccessEntryStatus { + if in == nil { + return nil + } + out := new(IPAccessEntryStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ManagedNamespace) DeepCopyInto(out *ManagedNamespace) { *out = *in diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index a894e12fac..4d53eada40 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1019,6 +1019,88 @@ func (in *AtlasFederatedAuthSpec) DeepCopy() *AtlasFederatedAuthSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AtlasIPAccessList) DeepCopyInto(out *AtlasIPAccessList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AtlasIPAccessList. +func (in *AtlasIPAccessList) DeepCopy() *AtlasIPAccessList { + if in == nil { + return nil + } + out := new(AtlasIPAccessList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AtlasIPAccessList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AtlasIPAccessListList) DeepCopyInto(out *AtlasIPAccessListList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AtlasIPAccessList, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AtlasIPAccessListList. +func (in *AtlasIPAccessListList) DeepCopy() *AtlasIPAccessListList { + if in == nil { + return nil + } + out := new(AtlasIPAccessListList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AtlasIPAccessListList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AtlasIPAccessListSpec) DeepCopyInto(out *AtlasIPAccessListSpec) { + *out = *in + in.ProjectDualReference.DeepCopyInto(&out.ProjectDualReference) + if in.Entries != nil { + in, out := &in.Entries, &out.Entries + *out = make([]IPAccessEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AtlasIPAccessListSpec. +func (in *AtlasIPAccessListSpec) DeepCopy() *AtlasIPAccessListSpec { + if in == nil { + return nil + } + out := new(AtlasIPAccessListSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AtlasNetworkPeeringConfig) DeepCopyInto(out *AtlasNetworkPeeringConfig) { *out = *in @@ -2395,6 +2477,25 @@ func (in *GoogleCloudKms) DeepCopy() *GoogleCloudKms { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAccessEntry) DeepCopyInto(out *IPAccessEntry) { + *out = *in + if in.DeleteAfterDate != nil { + in, out := &in.DeleteAfterDate, &out.DeleteAfterDate + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAccessEntry. +func (in *IPAccessEntry) DeepCopy() *IPAccessEntry { + if in == nil { + return nil + } + out := new(IPAccessEntry) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ManagedNamespace) DeepCopyInto(out *ManagedNamespace) { *out = *in diff --git a/config/crd/bases/atlas.mongodb.com_atlasipaccesslists.yaml b/config/crd/bases/atlas.mongodb.com_atlasipaccesslists.yaml new file mode 100644 index 0000000000..edd2c18011 --- /dev/null +++ b/config/crd/bases/atlas.mongodb.com_atlasipaccesslists.yaml @@ -0,0 +1,192 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: atlasipaccesslists.atlas.mongodb.com +spec: + group: atlas.mongodb.com + names: + categories: + - atlas + kind: AtlasIPAccessList + listKind: AtlasIPAccessListList + plural: atlasipaccesslists + shortNames: + - aial + singular: atlasipaccesslist + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1 + schema: + openAPIV3Schema: + description: AtlasIPAccessList is the Schema for the atlasipaccesslists API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AtlasIPAccessListSpec defines the desired state of AtlasIPAccessList. + properties: + connectionSecret: + description: Name of the secret containing Atlas API private and public + keys + properties: + name: + description: |- + Name of the resource being referred to + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + entries: + description: Entries is the list of IP Access to be managed + items: + properties: + awsSecurityGroup: + description: Unique identifier of AWS security group in this + access list entry. + type: string + cidrBlock: + description: Range of IP addresses in CIDR notation in this + access list entry. + type: string + comment: + description: Comment associated with this access list entry. + type: string + deleteAfterDate: + description: Date and time after which Atlas deletes the temporary + access list entry. + format: date-time + type: string + ipAddress: + description: Entry using an IP address in this access list entry. + type: string + type: object + x-kubernetes-validations: + - message: Only one of ipAddress, cidrBlock, or awsSecurityGroup + may be set. + rule: '!(has(self.ipAddress) && (has(self.cidrBlock) || has(self.awsSecurityGroup))) + && !(has(self.cidrBlock) && has(self.awsSecurityGroup))' + minItems: 1 + type: array + externalProjectRef: + description: |- + "externalProjectRef" holds the parent Atlas project ID. + Mutually exclusive with the "projectRef" field + properties: + id: + description: ID is the Atlas project ID + type: string + required: + - id + type: object + projectRef: + description: |- + "projectRef" is a reference to the parent AtlasProject resource. + Mutually exclusive with the "externalProjectRef" field + properties: + name: + description: Name is the name of the Kubernetes Resource + type: string + namespace: + description: Namespace is the namespace of the Kubernetes Resource + type: string + required: + - name + type: object + required: + - entries + type: object + x-kubernetes-validations: + - message: must define only one project reference through externalProjectRef + or projectRef + rule: (has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef) + && has(self.projectRef)) + - message: must define a local connection secret when referencing an external + project + rule: (has(self.externalProjectRef) && has(self.connectionSecret)) || + !has(self.externalProjectRef) + status: + description: AtlasIPAccessListStatus is the most recent observed status + of the AtlasIPAccessList cluster. Read-only. + properties: + conditions: + description: Conditions is the list of statuses showing the current + state of the Atlas Custom Resource + items: + description: Condition describes the state of an Atlas Custom Resource + at a certain point. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of Atlas Custom Resource condition. + type: string + required: + - status + - type + type: object + type: array + entries: + description: Status is the state of the ip access list + items: + properties: + entry: + description: Entry is the ip access Atlas is managing + type: string + status: + description: Status is the correspondent state of the entry + type: string + required: + - entry + - status + type: object + type: array + observedGeneration: + description: |- + ObservedGeneration indicates the generation of the resource specification that the Atlas Operator is aware of. + The Atlas Operator updates this field to the 'metadata.generation' as soon as it starts reconciliation of the resource. + format: int64 + type: integer + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 684f021ef6..911c4e25d3 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -16,5 +16,6 @@ resources: - bases/atlas.mongodb.com_atlasbackupcompliancepolicies.yaml - bases/atlas.mongodb.com_atlasprivateendpoints.yaml - bases/atlas.mongodb.com_atlascustomroles.yaml + - bases/atlas.mongodb.com_atlasipaccesslists.yaml configurations: - kustomizeconfig.yaml diff --git a/config/rbac/atlasipaccesslist_editor_role.yaml b/config/rbac/atlasipaccesslist_editor_role.yaml new file mode 100644 index 0000000000..a2024e1c5a --- /dev/null +++ b/config/rbac/atlasipaccesslist_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit atlasipaccesslists. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: mongodb-atlas-kubernetes + app.kubernetes.io/managed-by: kustomize + name: atlasipaccesslist-editor-role +rules: +- apiGroups: + - atlas.mongodb.com + resources: + - atlasipaccesslists + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - atlas.mongodb.com + resources: + - atlasipaccesslists/status + verbs: + - get diff --git a/config/rbac/atlasipaccesslist_viewer_role.yaml b/config/rbac/atlasipaccesslist_viewer_role.yaml new file mode 100644 index 0000000000..d11f75c292 --- /dev/null +++ b/config/rbac/atlasipaccesslist_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view atlasipaccesslists. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: mongodb-atlas-kubernetes + app.kubernetes.io/managed-by: kustomize + name: atlasipaccesslist-viewer-role +rules: +- apiGroups: + - atlas.mongodb.com + resources: + - atlasipaccesslists + verbs: + - get + - list + - watch +- apiGroups: + - atlas.mongodb.com + resources: + - atlasipaccesslists/status + verbs: + - get diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 72b6aba360..4694142350 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -22,6 +22,8 @@ resources: # default, aiding admins in cluster management. Those roles are # not used by the Project itself. You can comment the following lines # if you do not want those helpers be installed with your Project. +- atlasipaccesslist_editor_role.yaml +- atlasipaccesslist_viewer_role.yaml - atlascustomrole_editor_role.yaml - atlascustomrole_viewer_role.yaml - atlasprivateendpoint_editor_role.yaml diff --git a/config/samples/atlas_v1_atlasipaccesslist.yaml b/config/samples/atlas_v1_atlasipaccesslist.yaml new file mode 100644 index 0000000000..07b2bf8659 --- /dev/null +++ b/config/samples/atlas_v1_atlasipaccesslist.yaml @@ -0,0 +1,18 @@ +apiVersion: atlas.mongodb.com/v1 +kind: AtlasIPAccessList +metadata: + labels: + app.kubernetes.io/name: mongodb-atlas-kubernetes + app.kubernetes.io/managed-by: kustomize + name: atlasipaccesslist-sample +spec: + externalProjectRef: + id: p-123456 + connectionSecret: + name: my-secret + entries: + - cidrBlock: 192.168.1.0/24 + - ipAddress: 10.0.0.1 + deleteAfterDate: 2025-03-31T23:59:59+02:00 + - awsSecurityGroup: sg-1234 + comment: "AWS Access" \ No newline at end of file diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 2dcc484e99..c02899cacd 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -8,4 +8,5 @@ resources: - atlas_v1_atlasbackuppolicy.yaml - atlas_v1_atlasbackupschedule.yaml - atlas_v1_atlasteam.yaml + - atlas_v1_atlasipaccesslist.yaml # +kubebuilder:scaffold:manifestskustomizesamples