Skip to content

Commit 637a407

Browse files
authored
Static Firewall Deployments (#118)
1 parent f43c501 commit 637a407

31 files changed

+2879
-255
lines changed

DEVELOPMENT.md

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ Next install our CAPMS provider into the cluster.
1818
make push-to-capi-lab
1919
```
2020

21-
Before creating a cluster some manual steps are required beforehand: you need to allocate a node network and a firewall.
21+
Before creating a cluster some manual steps are required beforehand: you need to allocate a node network.
2222

2323
```bash
24-
make -C capi-lab node-network firewall control-plane-ip
24+
make -C capi-lab node-network control-plane-ip
2525
```
2626

2727
A basic cluster configuration that relies on `config/clusterctl-templates/cluster-template.yaml` and uses the aforementioned node network can be generated and applied to the management cluster using a make target.
@@ -181,16 +181,14 @@ export WORKER_MACHINE_COUNT=1
181181
export repo_path=$HOME/path/to/cluster-api-provider-metal-stack
182182
export project_name=
183183
export tenant_name=
184-
export firewall_id=
185184
```
186185

187-
Create firewall if needed:
186+
Create project, node network and control plane ip if needed:
188187

189188
```bash
190189
metalctl project create --name $project_name --tenant $tenant_name --description "Cluster API test project"
191190
metalctl network allocate --description "Node network for $CLUSTER_NAME" --name $CLUSTER_NAME --project $METAL_PROJECT_ID --partition $METAL_PARTITION
192191
metalctl network ip create --network internet --project $METAL_PROJECT_ID --name "$CLUSTER_NAME-vip" --type static -o template --template "{{ .ipaddress }}"
193-
metalctl firewall create --description "Firewall for $CLUSTER_NAME cluster" --name firewall-$CLUSTER_NAME --hostname firewall-$CLUSTER_NAME --project $METAL_PROJECT_ID --partition $METAL_PARTITION --image $FIREWALL_MACHINE_IMAGE --size $FIREWALL_MACHINE_SIZE --firewall-rules-file $repo_path/config/target-cluster/firewall-rules.yaml --networks internet,$METAL_NODE_NETWORK_ID
194192
```
195193

196194
```bash
@@ -201,12 +199,6 @@ clusterctl init --infrastructure metal-stack --kubeconfig kind-bootstrap.kubecon
201199
clusterctl generate cluster $CLUSTER_NAME --infrastructure metal-stack > cluster-$CLUSTER_NAME.yaml
202200
kubectl apply -n $NAMESPACE -f cluster-$CLUSTER_NAME.yaml
203201

204-
# once the control plane node is in phoned home
205-
metalctl machine consolepassword $firewall_id
206-
metalctl machine console --ipmi $firewall_id
207-
# sudo systemctl restart frr
208-
# ~.
209-
210202
kubectl --kubeconfig kind-bootstrap.kubeconfig -n $NAMESPACE get metalstackmachines.infrastructure.cluster.x-k8s.io
211203
export control_plane_machine_id=
212204
metalctl machine console --ipmi $control_plane_machine_id

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build the manager binary
2-
FROM golang:1.23 AS builder
2+
FROM golang:1.24 AS builder
33
ARG TARGETOS
44
ARG TARGETARCH
55

@@ -15,6 +15,7 @@ RUN go mod download
1515
COPY cmd/main.go cmd/main.go
1616
COPY api/ api/
1717
COPY internal/ internal/
18+
COPY util/ util/
1819

1920
# Build
2021
# the GOARCH has not a default value to allow the binary be built according to the host where the command

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ KUSTOMIZE_VERSION ?= v5.4.3
271271
CONTROLLER_TOOLS_VERSION ?= v0.16.4
272272
ENVTEST_VERSION ?= release-0.19
273273
GOLANGCI_LINT_VERSION ?= v1.61.0
274-
GINKGO_VERSION ?= v2.23.3
274+
GINKGO_VERSION ?= v2.23.4
275275

276276
.PHONY: kustomize
277277
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.

README.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ Currently, we provide the following custom resources:
1111

1212
- [`MetalStackCluster`](./api/v1alpha1/metalstackcluster_types.go) can be used as [infrastructure cluster](https://cluster-api.sigs.k8s.io/developer/providers/contracts/infra-cluster) and ensures that there is a control plane IP for the cluster.
1313
- [`MetalStackMachine`](./api/v1alpha1/metalstackmachine_types.go) bridges between [infrastructure machines](https://cluster-api.sigs.k8s.io/developer/providers/contracts/infra-machine) and metal-stack machines.
14+
- [`MetalStackMachineTemplate`](./api/v1alpha1/metalstackmachinetemplate_types.go) can be used to define reusable machine specifications for `MetalStackMachine` resources.
15+
- [`MetalStackFirewallDeployment`](./api/v1alpha1/metalstackfirewalldeployment_types.go) can be used to define firewall deployments for a cluster.
16+
- [`MetalStackFirewallTemplate`](./api/v1alpha1/metalstackfirewalltemplate_types.go) defines the configuration of deployed firewalls.
1417

1518
We plan to cover more resources in the future:
1619

1720
- Node Networks
18-
- Firewall Deployments
21+
- Complete Firewall Deployments using the [Firewall Controller Manager](https://github.com/metal-stack/firewall-controller-manager)
1922
- Improved configuration suggestion of CNIs
2023

2124
> [!note]
@@ -76,15 +79,6 @@ Allocate a VIP for the control plane.
7679
export CONTROL_PLANE_IP=$(metalctl network ip create --network internet --project $METAL_PROJECT_ID --name "$CLUSTER_NAME-vip" --type static -o template --template "{{ .ipaddress }}")
7780
```
7881

79-
A firewall needs to be created with appropriate firewall rules. An example can be found at [firewall-rules.yaml](config/target-cluster/firewall-rules.yaml).
80-
```bash
81-
# export environment variable for the firewall image and size
82-
export FIREWALL_MACHINE_IMAGE=<firewall-image>
83-
export FIREWALL_MACHINE_SIZE=<machine-size>
84-
85-
metalctl firewall create --description "Firewall for $CLUSTER_NAME" --name "$CLUSTER_NAME-fw" --hostname "$CLUSTER_NAME-fw" --project $METAL_PROJECT_ID --partition $METAL_PARTITION --image $FIREWALL_MACHINE_IMAGE --size $FIREWALL_MACHINE_SIZE --firewall-rules-file=<rules.yaml> --networks internet,$METAL_NODE_NETWORK_ID
86-
```
87-
8882
For your first cluster, it is advised to start with our generated template. Ensure that the namespaced cluster name is unique within the metal stack project.
8983

9084
```bash
@@ -96,6 +90,8 @@ export CONTROL_PLANE_MACHINE_IMAGE=<machine-image>
9690
export CONTROL_PLANE_MACHINE_SIZE=<machine-size>
9791
export WORKER_MACHINE_IMAGE=<machine-image>
9892
export WORKER_MACHINE_SIZE=<machine-size>
93+
export FIREWALL_MACHINE_IMAGE=<machine-image>
94+
export FIREWALL_MACHINE_SIZE=<machine-size>
9995

10096
# generate manifest
10197
clusterctl generate cluster $CLUSTER_NAME --kubernetes-version v1.32.9 --infrastructure metal-stack

api/v1alpha1/metalstackcluster_types.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,16 @@ import (
2828
)
2929

3030
const (
31+
MetalStackClusterKind = "MetalStackCluster"
3132
// ClusterFinalizer allows to clean up resources associated with before removing it from the apiserver.
3233
ClusterFinalizer = "metal-stack.infrastructure.cluster.x-k8s.io/cluster"
3334

3435
TagInfraClusterResource = "metal-stack.infrastructure.cluster.x-k8s.io/cluster-resource"
3536

3637
ClusterControlPlaneEndpointDefaultPort = 443
3738

38-
ClusterControlPlaneIPEnsured clusterv1.ConditionType = "ClusterControlPlaneIPEnsured"
3939
ClusterPaused clusterv1.ConditionType = clusterv1.PausedV1Beta2Condition
40+
ClusterControlPlaneIPEnsured clusterv1.ConditionType = "ClusterControlPlaneIPEnsured"
4041
)
4142

4243
var (
@@ -50,7 +51,7 @@ var (
5051
type MetalStackClusterSpec struct {
5152
// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
5253
// +optional
53-
ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint,omitempty"`
54+
ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint,omitzero"`
5455

5556
// ProjectID is the project id of the project in metal-stack in which the associated metal-stack resources are created.
5657
ProjectID string `json:"projectID"`
@@ -66,6 +67,17 @@ type MetalStackClusterSpec struct {
6667

6768
// Partition is the data center partition in which the resources are created.
6869
Partition string `json:"partition"`
70+
71+
// FirewallDeploymentRef references a MetalStackFirewallDeployment resource which manages the firewall for this cluster.
72+
// This feature is currently in public preview.
73+
// +optional
74+
FirewallDeploymentRef *MetalStackFirewallDeploymentRef `json:"firewallDeploymentRef,omitempty"`
75+
}
76+
77+
// MetalStackFirewallDeploymentRef contains a reference to a MetalStackFirewallDeployment resource.
78+
type MetalStackFirewallDeploymentRef struct {
79+
// Name is the name of the MetalStackFirewallDeployment resource.
80+
Name string `json:"name"`
6981
}
7082

7183
// APIEndpoint represents a reachable Kubernetes API endpoint.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
6+
)
7+
8+
const (
9+
MetalStackFirewallDeploymentKind = "MetalStackFirewallDeployment"
10+
// FirewallDeploymentFinalizer allows to clean up resources associated with before removing it from the apiserver.
11+
FirewallDeploymentFinalizer = "metal-stack.infrastructure.cluster.x-k8s.io/firewall-deployment"
12+
13+
TagFirewallDeploymentResource = "metal-stack.infrastructure.cluster.x-k8s.io/firewall-deployment-resource"
14+
15+
ClusterFirewallDeploymentEnsured clusterv1.ConditionType = "ClusterFirewallDeploymentEnsured"
16+
)
17+
18+
// MetalStackFirewallDeploymentSpec defines the desired state of MetalStackFirewallDeployment
19+
type MetalStackFirewallDeploymentSpec struct {
20+
// FirewallTemplateRef references the MetalStackFirewallTemplate to use for the firewall deployment.
21+
FirewallTemplateRef MetalStackFirewallTemplateRef `json:"firewallTemplateRef"`
22+
// ManagedResourceRef references the resource that represents the firewall deployment. At this moment it is a metal-stack firewall id.
23+
// It is planned to reference a FirewallDeployment.
24+
// +optional
25+
ManagedResourceRef *MetalStackManagedResourceRef `json:"managedResourceRef,omitempty"`
26+
27+
// AutoUpdate defines the behavior for automatic updates.
28+
AutoUpdate *MetalStackFirewallAutoUpdate `json:"autoUpdate,omitempty"`
29+
}
30+
31+
type MetalStackFirewallAutoUpdate struct {
32+
MachineImage bool `json:"machineImage,omitempty"`
33+
}
34+
35+
// MetalStackManagedResourceRef references a MetalStackManagedResource.
36+
type MetalStackManagedResourceRef struct {
37+
// Name of the MetalStackManagedResource.
38+
Name string `json:"name"`
39+
}
40+
41+
// MetalStackFirewallTemplateRef references a MetalStackFirewallTemplate.
42+
type MetalStackFirewallTemplateRef struct {
43+
// Name of the MetalStackFirewallTemplate.
44+
Name string `json:"name"`
45+
}
46+
47+
// MetalStackFirewallDeploymentStatus defines the observed state of MetalStackFirewallDeployment
48+
type MetalStackFirewallDeploymentStatus struct {
49+
// +kubebuilder:default=false
50+
Ready bool `json:"ready"`
51+
52+
// Conditions defines current service state of the MetalStackCluster.
53+
// +optional
54+
Conditions clusterv1.Conditions `json:"conditions,omitempty"`
55+
}
56+
57+
// +kubebuilder:object:root=true
58+
// +kubebuilder:subresource:status
59+
// +kubebuilder:resource:scope=Namespaced,categories=cluster-api,shortName=msfwdeploy
60+
// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.cluster\\.x-k8s\\.io/cluster-name",description="Cluster to which this MetalStackCluster belongs"
61+
// +kubebuilder:printcolumn:name="Template",type="string",JSONPath=".spec.firewallTemplateRef.name",description="Name of the MetalStackFirewallTemplate used"
62+
// +kubebuilder:printcolumn:name="Deployment",type="string",JSONPath=".spec.managedResourceRef.name",description="Name of the managed FirewallDeployment"
63+
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.ready",description="Indicates if the MetalStackFirewallDeployment is ready"
64+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age of the MetalStackFirewallDeployment"
65+
66+
// MetalStackFirewallDeployment is the Schema for the MetalStackFirewallDeployments API
67+
type MetalStackFirewallDeployment struct {
68+
metav1.TypeMeta `json:",inline"`
69+
metav1.ObjectMeta `json:"metadata,omitempty"`
70+
71+
Spec MetalStackFirewallDeploymentSpec `json:"spec,omitzero"`
72+
Status MetalStackFirewallDeploymentStatus `json:"status,omitempty"`
73+
}
74+
75+
// +kubebuilder:object:root=true
76+
77+
type MetalStackFirewallDeploymentList struct {
78+
metav1.TypeMeta `json:",inline"`
79+
metav1.ListMeta `json:"metadata,omitempty"`
80+
Items []MetalStackFirewallDeployment `json:"items"`
81+
}
82+
83+
func init() {
84+
SchemeBuilder.Register(&MetalStackFirewallDeployment{}, &MetalStackFirewallDeploymentList{})
85+
}
86+
87+
func (c *MetalStackFirewallDeployment) GetConditions() clusterv1.Conditions {
88+
return c.Status.Conditions
89+
}
90+
91+
func (c *MetalStackFirewallDeployment) SetConditions(conditions clusterv1.Conditions) {
92+
c.Status.Conditions = conditions
93+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package v1alpha1
2+
3+
import (
4+
fcmv2 "github.com/metal-stack/firewall-controller-manager/api/v2"
5+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6+
)
7+
8+
const (
9+
MetalStackFirewallTemplateKind = "MetalStackFirewallTemplate"
10+
)
11+
12+
// +kubebuilder:object:root=true
13+
// +kubebuilder:subresource:status
14+
// +kubebuilder:resource:scope=Namespaced,categories=cluster-api,shortName=msfwtemplate
15+
// +kubebuilder:printcolumn:name="Partition",type="string",JSONPath=".spec.partition",description="The Metal Stack partition where the firewall will be created"
16+
// +kubebuilder:printcolumn:name="Project",type="string",JSONPath=".spec.project",description="The Metal Stack project where the firewall will be created"
17+
// +kubebuilder:printcolumn:name="Image",type="string",JSONPath=".spec.image",description="The Metal Stack firewall image"
18+
// +kubebuilder:printcolumn:name="Size",type="string",JSONPath=".spec.size",description="The Metal Stack firewall size"
19+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the firewall template"
20+
type MetalStackFirewallTemplate struct {
21+
metav1.TypeMeta `json:",inline"`
22+
metav1.ObjectMeta `json:"metadata,omitempty"`
23+
24+
// Spec defines the firewall deployment template spec used to create firewalls for the cluster.
25+
Spec fcmv2.FirewallSpec `json:"spec"`
26+
}
27+
28+
// +kubebuilder:object:root=true
29+
30+
type MetalStackFirewallTemplateList struct {
31+
metav1.TypeMeta `json:",inline"`
32+
metav1.ListMeta `json:"metadata,omitempty"`
33+
Items []MetalStackFirewallTemplate `json:"items"`
34+
}
35+
36+
func init() {
37+
SchemeBuilder.Register(&MetalStackFirewallTemplate{}, &MetalStackFirewallTemplateList{})
38+
}

api/v1alpha1/metalstackmachine_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
)
2424

2525
const (
26+
MetalStackMachineKind = "MetalStackMachine"
2627
// MachineFinalizer allows to clean up resources associated with before removing it from the apiserver.
2728
MachineFinalizer = "metal-stack.infrastructure.cluster.x-k8s.io/machine"
2829

0 commit comments

Comments
 (0)