Skip to content

Commit

Permalink
New API for SecurityGroups
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilienM committed Nov 23, 2023
1 parent fc7ba6e commit 0dedf43
Show file tree
Hide file tree
Showing 12 changed files with 520 additions and 3 deletions.
1 change: 1 addition & 0 deletions api/v1alpha5/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/v1alpha6/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/v1alpha7/openstackcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ type OpenStackClusterSpec struct {
// +optional
ManagedSecurityGroups bool `json:"managedSecurityGroups"`

// SecurityGroups contains the security groups to be used for the cluster.
// This can be used to let CAPO manage the security groups for the cluster.
// +optional
SecurityGroups *SecurityGroupSpec `json:"securityGroups,omitempty"`

// AllowAllInClusterTraffic is only used when managed security groups are in use.
// If set to true, the rules for the managed security groups are configured so that all
// ingress and egress between cluster nodes is permitted, allowing CNIs other than
Expand Down
9 changes: 9 additions & 0 deletions api/v1alpha7/openstackcluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ func (r *OpenStackCluster) ValidateCreate() (admission.Warnings, error) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "identityRef", "kind"), "must be a Secret"))
}

// Ensure that ManagedSecurityGroups is not set if SecurityGroups is set.
if r.Spec.SecurityGroups != nil && r.Spec.ManagedSecurityGroups {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "managedSecurityGroups"), "cannot be set if spec.securityGroups is set"))
}

return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs)
}

Expand Down Expand Up @@ -134,6 +139,10 @@ func (r *OpenStackCluster) ValidateUpdate(oldRaw runtime.Object) (admission.Warn
old.Spec.AllowAllInClusterTraffic = false
r.Spec.AllowAllInClusterTraffic = false

// Allow change to the security groups.
old.Spec.SecurityGroups = nil
r.Spec.SecurityGroups = nil

// Allow change on the spec.APIServerFloatingIP only if it matches the current api server loadbalancer IP.
if old.Status.APIServerLoadBalancer != nil && r.Spec.APIServerFloatingIP == old.Status.APIServerLoadBalancer.IP {
r.Spec.APIServerFloatingIP = ""
Expand Down
107 changes: 107 additions & 0 deletions api/v1alpha7/openstackcluster_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,92 @@ func TestOpenStackCluster_ValidateUpdate(t *testing.T) {
},
wantErr: false,
},
{
name: "Adding OpenStackCluster.Spec.SecurityGroups is allowed",
oldTemplate: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
},
},
newTemplate: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
SecurityGroups: &SecurityGroupSpec{
ControlPlaneSecurityGroupRules: []SecurityGroupRule{
{
Description: "Allow SSH",
Protocol: "tcp",
PortRangeMin: 22,
PortRangeMax: 22,
Direction: "ingress",
},
},
},
},
},
wantErr: false,
},
{
name: "Modifying OpenStackCluster.Spec.SecurityGroups is allowed",
oldTemplate: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
SecurityGroups: &SecurityGroupSpec{
ControlPlaneSecurityGroupRules: []SecurityGroupRule{
{
Description: "Allow SSH",
Protocol: "tcp",
PortRangeMin: 22,
PortRangeMax: 22,
Direction: "ingress",
},
},
},
},
},
newTemplate: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
SecurityGroups: &SecurityGroupSpec{
ControlPlaneSecurityGroupRules: []SecurityGroupRule{
{
Description: "Allow SSH",
Protocol: "tcp",
PortRangeMin: 22,
PortRangeMax: 23,
Direction: "ingress",
},
},
},
},
},
wantErr: false,
},
{
name: "Removing OpenStackCluster.Spec.SecurityGroups is allowed",
oldTemplate: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
SecurityGroups: &SecurityGroupSpec{
ControlPlaneSecurityGroupRules: []SecurityGroupRule{
{
Description: "Allow SSH",
Protocol: "tcp",
PortRangeMin: 22,
PortRangeMax: 23,
Direction: "ingress",
},
},
},
},
},
newTemplate: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
},
},
wantErr: false,
},
{
name: "Changing OpenStackCluster.Spec.APIServerFixedIP is allowed when API Server Floating IP is disabled",
oldTemplate: &OpenStackCluster{
Expand Down Expand Up @@ -392,6 +478,27 @@ func TestOpenStackCluster_ValidateCreate(t *testing.T) {
},
wantErr: true,
},
{
name: "OpenStackCluster.Spec.ManagedSecurityGroups and OpenStackCluster.Spec.SecurityGroups are not allowed to be set at the same time",
template: &OpenStackCluster{
Spec: OpenStackClusterSpec{
CloudName: "foobar",
ManagedSecurityGroups: true,
SecurityGroups: &SecurityGroupSpec{
ControlPlaneSecurityGroupRules: []SecurityGroupRule{
{
Description: "Allow SSH",
Protocol: "tcp",
PortRangeMin: 22,
PortRangeMax: 22,
Direction: "ingress",
},
},
},
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
23 changes: 23 additions & 0 deletions api/v1alpha7/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,29 @@ type APIServerLoadBalancer struct {
Provider string `json:"provider,omitempty"`
}

// SecurityGroupSpec represents the security group rules for the control plane and worker nodes.
type SecurityGroupSpec struct {
// BastionSecurityGroup contains all the information about the OpenStack Security
// Group that needs to be applied to bastion nodes.
// By default, we will create a security group with rules that allow SSH access.
// +optional
BastionSecurityGroupRules []SecurityGroupRule `json:"bastionSecurityGroupRules,omitempty"`

// ControlPlaneSecurityGroup contains all the information about the OpenStack Security
// Group that needs to be applied to control plane nodes.
// By default, we will create a security group with rules that allow the Kubelet, etcd and
// the Kubernetes API server to function correctly.
// +optional
ControlPlaneSecurityGroupRules []SecurityGroupRule `json:"controlPlaneSecurityGroupRules,omitempty"`

// WorkerSecurityGroup contains all the information about the OpenStack Security
// Group that needs to be applied to worker nodes.
// By default, we will create a security group with rules that allow the Kubelet to
// function correctly.
// +optional
WorkerSecurityGroupRules []SecurityGroupRule `json:"workerSecurityGroupRules,omitempty"`
}

// ValueSpec represents a single value_spec key-value pair.
type ValueSpec struct {
// Name is the name of the key-value pair.
Expand Down
35 changes: 35 additions & 0 deletions api/v1alpha7/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4327,6 +4327,139 @@ spec:
tagsAny:
type: string
type: object
securityGroups:
description: SecurityGroups contains the security groups to be used
for the cluster. This can be used to let CAPO manage the security
groups for the cluster.
properties:
bastionSecurityGroupRules:
description: BastionSecurityGroup contains all the information
about the OpenStack Security Group that needs to be applied
to bastion nodes. By default, we will create a security group
with rules that allow SSH access.
items:
description: SecurityGroupRule represent the basic information
of the associated OpenStack Security Group Role.
properties:
description:
type: string
direction:
type: string
etherType:
type: string
name:
type: string
portRangeMax:
type: integer
portRangeMin:
type: integer
protocol:
type: string
remoteGroupID:
type: string
remoteIPPrefix:
type: string
securityGroupID:
type: string
required:
- description
- direction
- etherType
- name
- portRangeMax
- portRangeMin
- protocol
- remoteGroupID
- remoteIPPrefix
- securityGroupID
type: object
type: array
controlPlaneSecurityGroupRules:
description: ControlPlaneSecurityGroup contains all the information
about the OpenStack Security Group that needs to be applied
to control plane nodes. By default, we will create a security
group with rules that allow the Kubelet, etcd and the Kubernetes
API server to function correctly.
items:
description: SecurityGroupRule represent the basic information
of the associated OpenStack Security Group Role.
properties:
description:
type: string
direction:
type: string
etherType:
type: string
name:
type: string
portRangeMax:
type: integer
portRangeMin:
type: integer
protocol:
type: string
remoteGroupID:
type: string
remoteIPPrefix:
type: string
securityGroupID:
type: string
required:
- description
- direction
- etherType
- name
- portRangeMax
- portRangeMin
- protocol
- remoteGroupID
- remoteIPPrefix
- securityGroupID
type: object
type: array
workerSecurityGroupRules:
description: WorkerSecurityGroup contains all the information
about the OpenStack Security Group that needs to be applied
to worker nodes. By default, we will create a security group
with rules that allow the Kubelet to function correctly.
items:
description: SecurityGroupRule represent the basic information
of the associated OpenStack Security Group Role.
properties:
description:
type: string
direction:
type: string
etherType:
type: string
name:
type: string
portRangeMax:
type: integer
portRangeMin:
type: integer
protocol:
type: string
remoteGroupID:
type: string
remoteIPPrefix:
type: string
securityGroupID:
type: string
required:
- description
- direction
- etherType
- name
- portRangeMax
- portRangeMin
- protocol
- remoteGroupID
- remoteIPPrefix
- securityGroupID
type: object
type: array
type: object
subnet:
description: If NodeCIDR cannot be set this can be used to detect
an existing subnet.
Expand Down
Loading

0 comments on commit 0dedf43

Please sign in to comment.