Skip to content

Commit

Permalink
Merge branch 'master' into support-flowtables
Browse files Browse the repository at this point in the history
  • Loading branch information
majst01 authored Mar 21, 2024
2 parents 82dc142 + 118b30e commit 7aeb212
Show file tree
Hide file tree
Showing 33 changed files with 1,140 additions and 662 deletions.
22 changes: 12 additions & 10 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ jobs:

steps:
- name: Log in to the container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_REGISTRY_USER }}
password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}

- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- uses: google-github-actions/auth@v1
with:
Expand All @@ -39,10 +39,11 @@ jobs:
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v0

- name: Set up Go 1.20
uses: actions/setup-go@v4
- name: Set up Go 1.21
uses: actions/setup-go@v5
with:
go-version: '1.20'
go-version: '1.21'
cache: false

- name: Lint
uses: golangci/golangci-lint-action@v3
Expand All @@ -64,7 +65,7 @@ jobs:
make
- name: Push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
push: true
Expand All @@ -89,12 +90,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Set up Go 1.20
uses: actions/setup-go@v4
- name: Set up Go 1.21
uses: actions/setup-go@v5
with:
go-version: '1.20'
go-version: '1.21'
cache: false

- name: Run tests
run: |
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ GITVERSION := $(shell git describe --long --all)
BUILDDATE := $(shell date -Iseconds)
VERSION := $(or ${VERSION},$(shell git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q --short HEAD || git rev-parse --short HEAD))

CONTROLLER_TOOLS_VERSION ?= v0.11.3
CONTROLLER_TOOLS_VERSION ?= v0.13.0
LOCALBIN ?= $(shell pwd)/bin
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
Expand Down
16 changes: 16 additions & 0 deletions api/v1/clusterwidenetworkpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const (
// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=cwnp
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.state"
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message"
type ClusterwideNetworkPolicy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down Expand Up @@ -67,12 +69,26 @@ type PolicySpec struct {

type FQDNState map[string][]IPSet

// PolicyDeploymentState describes the state of a CWNP deployment
type PolicyDeploymentState string

const (
// PolicyDeploymentStateDeployed the CWNP was deployed to a native nftable rule
PolicyDeploymentStateDeployed = PolicyDeploymentState("deployed")
// PolicyDeploymentStateIgnored the CWNP was not deployed to a native nftable rule because it is outside of allowed networks
PolicyDeploymentStateIgnored = PolicyDeploymentState("ignored")
)

// PolicyStatus defines the observed state for CWNP resource
type PolicyStatus struct {
// FQDNState stores mapping from FQDN rules to nftables sets used for a firewall rule.
// Key is either MatchName or MatchPattern
// +optional
FQDNState FQDNState `json:"fqdn_state,omitempty"`
// State of the CWNP, can be either deployed or ignored
State PolicyDeploymentState `json:"state,omitempty"`
// Message describes why the state changed
Message string `json:"message,omitempty"`
}

// IngressRule describes a particular set of traffic that is allowed to the cluster.
Expand Down
7 changes: 4 additions & 3 deletions api/v1/zz_generated.deepcopy.go

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

18 changes: 15 additions & 3 deletions config/crd/bases/metal-stack.io_clusterwidenetworkpolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.3
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: clusterwidenetworkpolicies.metal-stack.io
spec:
group: metal-stack.io
Expand All @@ -17,7 +16,14 @@ spec:
singular: clusterwidenetworkpolicy
scope: Namespaced
versions:
- name: v1
- additionalPrinterColumns:
- jsonPath: .status.state
name: Status
type: string
- jsonPath: .status.message
name: Message
type: string
name: v1
schema:
openAPIV3Schema:
description: ClusterwideNetworkPolicy contains the desired state for a cluster
Expand Down Expand Up @@ -252,6 +258,12 @@ spec:
description: FQDNState stores mapping from FQDN rules to nftables
sets used for a firewall rule. Key is either MatchName or MatchPattern
type: object
message:
description: Message describes why the state changed
type: string
state:
description: State of the CWNP, can be either deployed or ignored
type: string
type: object
type: object
served: true
Expand Down
1 change: 0 additions & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
Expand Down
105 changes: 98 additions & 7 deletions controllers/clusterwidenetworkpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import (
"fmt"
"time"

"github.com/metal-stack/firewall-controller/pkg/dns"
"github.com/metal-stack/firewall-controller/pkg/nftables"
"go4.org/netipx"

"github.com/metal-stack/firewall-controller/v2/pkg/dns"
"github.com/metal-stack/firewall-controller/v2/pkg/helper"
"github.com/metal-stack/firewall-controller/v2/pkg/nftables"

"github.com/go-logr/logr"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -21,7 +25,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"

firewallv2 "github.com/metal-stack/firewall-controller-manager/api/v2"
firewallv1 "github.com/metal-stack/firewall-controller/api/v1"
firewallv1 "github.com/metal-stack/firewall-controller/v2/api/v1"
)

// ClusterwideNetworkPolicyReconciler reconciles a ClusterwideNetworkPolicy object
Expand All @@ -33,7 +37,8 @@ type ClusterwideNetworkPolicyReconciler struct {
FirewallName string
SeedNamespace string

Log logr.Logger
Log logr.Logger
Recorder record.EventRecorder

Interval time.Duration
DnsProxy *dns.DNSProxy
Expand Down Expand Up @@ -91,7 +96,14 @@ func (r *ClusterwideNetworkPolicyReconciler) Reconcile(ctx context.Context, _ ct
if err := r.ShootClient.List(ctx, &services); err != nil {
return ctrl.Result{}, err
}
nftablesFirewall := nftables.NewFirewall(f, &cwnps, &services, r.DnsProxy, r.Log)

validCwnps, err := r.allowedCWNPs(ctx, cwnps.Items, f.Spec.AllowedNetworks)
if err != nil {
return ctrl.Result{}, err
}
cwnps.Items = validCwnps

nftablesFirewall := nftables.NewFirewall(f, &cwnps, &services, r.DnsProxy, r.Log, r.Recorder)
if err := r.manageDNSProxy(ctx, f, cwnps, nftablesFirewall); err != nil {
return ctrl.Result{}, err
}
Expand All @@ -103,8 +115,8 @@ func (r *ClusterwideNetworkPolicyReconciler) Reconcile(ctx context.Context, _ ct
if updated {
for _, i := range cwnps.Items {
o := i
if err := r.ShootClient.Status().Update(ctx, &o); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to updated CWNP status: %w", err)
if err := r.updateCWNPState(ctx, o, firewallv1.PolicyDeploymentStateDeployed, ""); err != nil {
return ctrl.Result{}, err
}
}
}
Expand Down Expand Up @@ -181,3 +193,82 @@ func (r *ClusterwideNetworkPolicyReconciler) getReconciliationTicker(scheduleCha
}
}
}

func (r *ClusterwideNetworkPolicyReconciler) allowedCWNPs(ctx context.Context, cwnps []firewallv1.ClusterwideNetworkPolicy, allowedNetworks firewallv2.AllowedNetworks) ([]firewallv1.ClusterwideNetworkPolicy, error) {
if len(allowedNetworks.Egress) == 0 && len(allowedNetworks.Ingress) == 0 {
return cwnps, nil
}

validCWNPs := make([]firewallv1.ClusterwideNetworkPolicy, 0, len(cwnps))

egressSet, err := helper.BuildNetworksIPSet(allowedNetworks.Egress)
if err != nil {
return nil, err
}

ingressSet, err := helper.BuildNetworksIPSet(allowedNetworks.Ingress)
if err != nil {
return nil, err
}

for _, cwnp := range cwnps {
cwnp := cwnp
oke, err := r.validateCWNPEgressTargetPrefix(cwnp, egressSet)
if err != nil {
return nil, err
}
oki, err := r.validateCWNPIngressTargetPrefix(cwnp, ingressSet)
if err != nil {
return nil, err
}

if !oki || !oke {
// at least one of ingress and/or egress is not in the allowed network set
if err := r.updateCWNPState(ctx, cwnp, firewallv1.PolicyDeploymentStateIgnored, "ingress/egress does not match allowed networks"); err != nil {
return nil, err
}
continue
}

validCWNPs = append(validCWNPs, cwnp)
}

return validCWNPs, nil
}

func (r *ClusterwideNetworkPolicyReconciler) updateCWNPState(ctx context.Context, cwnp firewallv1.ClusterwideNetworkPolicy, state firewallv1.PolicyDeploymentState, msg string) error {
// do nothing if message and state already have the desired values
if cwnp.Status.Message == msg && cwnp.Status.State == state {
return nil
}

cwnp.Status.Message = msg
cwnp.Status.State = state

if err := r.ShootClient.Status().Update(ctx, &cwnp); err != nil {
return fmt.Errorf("failed to update status of CWNP %q to %q: %w", cwnp.Name, state, err)
}
return nil
}

func (r *ClusterwideNetworkPolicyReconciler) validateCWNPEgressTargetPrefix(cwnp firewallv1.ClusterwideNetworkPolicy, ipSet *netipx.IPSet) (bool, error) {
for _, egress := range cwnp.Spec.Egress {
for _, to := range egress.To {
if ok, err := helper.ValidateCIDR(&cwnp, to.CIDR, ipSet, r.Recorder); !ok {
return false, err
}
}
}
return true, nil
}

func (r *ClusterwideNetworkPolicyReconciler) validateCWNPIngressTargetPrefix(cwnp firewallv1.ClusterwideNetworkPolicy, ipSet *netipx.IPSet) (bool, error) {
for _, ingress := range cwnp.Spec.Ingress {
for _, from := range ingress.From {
if ok, err := helper.ValidateCIDR(&cwnp, from.CIDR, ipSet, r.Recorder); !ok {
return false, err
}
}
}
return true, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

firewallv1 "github.com/metal-stack/firewall-controller/api/v1"
firewallv1 "github.com/metal-stack/firewall-controller/v2/api/v1"
)

// ClusterwideNetworkPolicyValidationReconciler validates a ClusterwideNetworkPolicy object
Expand Down
28 changes: 11 additions & 17 deletions controllers/droptailer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"

"github.com/go-logr/logr"
firewallv1 "github.com/metal-stack/firewall-controller/api/v1"
"github.com/metal-stack/gardener-extension-provider-metal/pkg/secret"
firewallv1 "github.com/metal-stack/firewall-controller/v2/api/v1"

"github.com/txn2/txeh"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -141,11 +141,17 @@ func (r *DroptailerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, nil
}

secret, err := getLatestSecret(ctx, r.ShootClient, firewallv1.ClusterwideNetworkPolicyNamespace, secretName)
if err != nil {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: firewallv1.ClusterwideNetworkPolicyNamespace,
},
}
if err := r.ShootClient.Get(ctx, client.ObjectKeyFromObject(secret), secret); err != nil {
return ctrl.Result{}, err
}
err = r.writeSecret(secret)

err := r.writeSecret(secret)
if err != nil {
return ctrl.Result{}, err
}
Expand Down Expand Up @@ -222,15 +228,3 @@ func (r *DroptailerReconciler) writeSecret(secret *corev1.Secret) error {
}
return nil
}

func getLatestSecret(ctx context.Context, c client.Client, namespace string, name string) (*corev1.Secret, error) {
secretList := &corev1.SecretList{}
if err := c.List(ctx, secretList, client.InNamespace(namespace), client.MatchingLabels{
"name": name,
"managed-by": "secrets-manager",
}); err != nil {
return nil, err
}

return secret.GetLatestIssuedSecret(secretList.Items)
}
Loading

0 comments on commit 7aeb212

Please sign in to comment.