Skip to content

Commit

Permalink
Support master authorized network config (#65)
Browse files Browse the repository at this point in the history
* add MasterAuthorizedNetworksConfig filed into GCPManagedControlPlane CRD

* fix

* disable it if no desired specified in CR

* change to do not reconcile if the desired CR is nil

* add comment
  • Loading branch information
yuecong committed Aug 15, 2023
1 parent 0b3039f commit 15805f8
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 4 deletions.
62 changes: 58 additions & 4 deletions cloud/services/container/clusters/reconcile.go
Expand Up @@ -19,6 +19,7 @@ package clusters
import (
"context"
"fmt"
"reflect"

"sigs.k8s.io/cluster-api-provider-gcp/cloud/scope"
"sigs.k8s.io/cluster-api-provider-gcp/cloud/services/shared"
Expand Down Expand Up @@ -136,7 +137,7 @@ func (s *Service) Reconcile(ctx context.Context) (ctrl.Result, error) {
return ctrl.Result{}, statusErr
}

needUpdate, updateClusterRequest := s.checkDiffAndPrepareUpdate(cluster)
needUpdate, updateClusterRequest := s.checkDiffAndPrepareUpdate(cluster, &log)
if needUpdate {
log.Info("Update required")
err = s.updateCluster(ctx, updateClusterRequest, &log)
Expand Down Expand Up @@ -258,6 +259,7 @@ func (s *Service) createCluster(ctx context.Context, log *logr.Logger) error {
ReleaseChannel: &containerpb.ReleaseChannel{
Channel: convertToSdkReleaseChannel(s.scope.GCPManagedControlPlane.Spec.ReleaseChannel),
},
MasterAuthorizedNetworksConfig: convertToSdkMasterAuthorizedNetworksConfig(s.scope.GCPManagedControlPlane.Spec.MasterAuthorizedNetworksConfig),
}
if s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion != nil {
cluster.InitialClusterVersion = *s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion
Expand Down Expand Up @@ -320,25 +322,77 @@ func convertToSdkReleaseChannel(channel *infrav1exp.ReleaseChannel) containerpb.
}
}

func (s *Service) checkDiffAndPrepareUpdate(existingCluster *containerpb.Cluster) (bool, *containerpb.UpdateClusterRequest) {
// convertToSdkMasterAuthorizedNetworksConfig converts the MasterAuthorizedNetworksConfig defined in CRs to the SDK version.
func convertToSdkMasterAuthorizedNetworksConfig(config *infrav1exp.MasterAuthorizedNetworksConfig) *containerpb.MasterAuthorizedNetworksConfig {
if config == nil {
return nil
}

// Convert the CidrBlocks slice.
cidrBlocks := make([]*containerpb.MasterAuthorizedNetworksConfig_CidrBlock, len(config.CidrBlocks))
for i, cidrBlock := range config.CidrBlocks {
cidrBlocks[i] = &containerpb.MasterAuthorizedNetworksConfig_CidrBlock{
CidrBlock: cidrBlock.CidrBlock,
DisplayName: cidrBlock.DisplayName,
}
}

return &containerpb.MasterAuthorizedNetworksConfig{
// Enabled specifies whether master authorized networks is enabled.
Enabled: config.Enabled,

// CidrBlocks specifies the list of CIDR blocks.
CidrBlocks: cidrBlocks,

// GcpPublicCidrsAccessEnabled specifies whether access to the public GCP-managed
// CIDRs block is enabled or not.
GcpPublicCidrsAccessEnabled: config.GcpPublicCidrsAccessEnabled,
}
}

func (s *Service) checkDiffAndPrepareUpdate(existingCluster *containerpb.Cluster, log *logr.Logger) (bool, *containerpb.UpdateClusterRequest) {
log.V(4).Info("Checking diff and preparing update.")

needUpdate := false
clusterUpdate := containerpb.ClusterUpdate{}
// Release channel
desiredReleaseChannel := convertToSdkReleaseChannel(s.scope.GCPManagedControlPlane.Spec.ReleaseChannel)
if desiredReleaseChannel != existingCluster.ReleaseChannel.Channel {
log.V(2).Info("Release channel update required", "current", existingCluster.ReleaseChannel.Channel, "desired", desiredReleaseChannel)
needUpdate = true
clusterUpdate.DesiredReleaseChannel = &containerpb.ReleaseChannel{
Channel: desiredReleaseChannel,
}
}
// Master version
if s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion != nil && *s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion != existingCluster.InitialClusterVersion {
if s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion != nil {
desiredMasterVersion := *s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion
if desiredMasterVersion != existingCluster.InitialClusterVersion {
needUpdate = true
clusterUpdate.DesiredMasterVersion = desiredMasterVersion
log.V(2).Info("Master version update required", "current", existingCluster.InitialClusterVersion, "desired", desiredMasterVersion)
}
}

// DesiredMasterAuthorizedNetworksConfig
// When desiredMasterAuthorizedNetworksConfig is nil, we will not update the existing config because this will casuse always reconcile.
// The GCP SDK is not allowed to pass nil to the update request either.
desiredMasterAuthorizedNetworksConfig := convertToSdkMasterAuthorizedNetworksConfig(s.scope.GCPManagedControlPlane.Spec.MasterAuthorizedNetworksConfig)
if desiredMasterAuthorizedNetworksConfig != nil && !reflect.DeepEqual(desiredMasterAuthorizedNetworksConfig, existingCluster.MasterAuthorizedNetworksConfig) {
needUpdate = true
clusterUpdate.DesiredMasterVersion = *s.scope.GCPManagedControlPlane.Spec.ControlPlaneVersion
clusterUpdate.DesiredMasterAuthorizedNetworksConfig = desiredMasterAuthorizedNetworksConfig
log.V(2).Info("Master authorized networks config update required", "current", existingCluster.MasterAuthorizedNetworksConfig, "desired", desiredMasterAuthorizedNetworksConfig)
}

log.V(4).Info("Master authorized networks config update check", "current", existingCluster.MasterAuthorizedNetworksConfig)
if desiredMasterAuthorizedNetworksConfig != nil {
log.V(4).Info("Master authorized networks config update check", "desired", desiredMasterAuthorizedNetworksConfig)
}

updateClusterRequest := containerpb.UpdateClusterRequest{
Name: s.scope.ClusterFullName(),
Update: &clusterUpdate,
}
log.V(4).Info("Update cluster request. ", "needUpdate", needUpdate, "updateClusterRequest", &updateClusterRequest)
return needUpdate, &updateClusterRequest
}
Expand Up @@ -91,6 +91,35 @@ spec:
description: Location represents the location (region or zone) in
which the GKE cluster will be created.
type: string
master_authorized_networks_config:
description: MasterAuthorizedNetworksConfig repsesents configuration
options for master authorized networks feature of the GKE cluster.
properties:
cidr_blocks:
description: cidr_blocks define up to 50 external networks that
could access Kubernetes master through HTTPS.
items:
description: MasterAuthorizedNetworksConfigCidrBlock contains
an optional name and one CIDR block.
properties:
cidr_block:
description: cidr_block must be specified in CIDR notation.
pattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?:\/([0-9]|[1-2][0-9]|3[0-2]))?$|^([a-fA-F0-9:]+:+)+[a-fA-F0-9]+\/[0-9]{1,3}$
type: string
display_name:
description: display_name is an optional field for users
to identify CIDR blocks.
type: string
type: object
type: array
enabled:
description: Whether or not master authorized networks is enabled.
type: boolean
gcp_public_cidrs_access_enabled:
description: Whether master is accessible via Google Compute Engine
Public IP addresses.
type: boolean
type: object
project:
description: Project is the name of the project to deploy the cluster
to.
Expand Down
27 changes: 27 additions & 0 deletions exp/api/v1beta1/gcpmanagedcontrolplane_types.go
Expand Up @@ -53,6 +53,9 @@ type GCPManagedControlPlaneSpec struct {
// Endpoint represents the endpoint used to communicate with the control plane.
// +optional
Endpoint clusterv1.APIEndpoint `json:"endpoint"`
// MasterAuthorizedNetworksConfig repsesents configuration options for master authorized networks feature of the GKE cluster.
// +optional
MasterAuthorizedNetworksConfig *MasterAuthorizedNetworksConfig `json:"master_authorized_networks_config,omitempty"`
}

// GCPManagedControlPlaneStatus defines the observed state of GCPManagedControlPlane.
Expand Down Expand Up @@ -115,6 +118,30 @@ const (
Stable ReleaseChannel = "stable"
)

// MasterAuthorizedNetworksConfig contains configuration options for the master authorized networks feature.
// Enabled master authorized networks will disallow all external traffic to access
// Kubernetes master through HTTPS except traffic from the given CIDR blocks,
// Google Compute Engine Public IPs and Google Prod IPs.
type MasterAuthorizedNetworksConfig struct {
// Whether or not master authorized networks is enabled.
Enabled bool `json:"enabled,omitempty"`
// cidr_blocks define up to 50 external networks that could access
// Kubernetes master through HTTPS.
CidrBlocks []*MasterAuthorizedNetworksConfigCidrBlock `json:"cidr_blocks,omitempty"`
// Whether master is accessible via Google Compute Engine Public IP addresses.
GcpPublicCidrsAccessEnabled *bool `json:"gcp_public_cidrs_access_enabled,omitempty"`
}

// MasterAuthorizedNetworksConfigCidrBlock contains an optional name and one CIDR block.
type MasterAuthorizedNetworksConfigCidrBlock struct {

// display_name is an optional field for users to identify CIDR blocks.
DisplayName string `json:"display_name,omitempty"`
// cidr_block must be specified in CIDR notation.
// +kubebuilder:validation:Pattern=`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?:\/([0-9]|[1-2][0-9]|3[0-2]))?$|^([a-fA-F0-9:]+:+)+[a-fA-F0-9]+\/[0-9]{1,3}$`
CidrBlock string `json:"cidr_block,omitempty"`
}

// GetConditions returns the control planes conditions.
func (r *GCPManagedControlPlane) GetConditions() clusterv1.Conditions {
return r.Status.Conditions
Expand Down
51 changes: 51 additions & 0 deletions exp/api/v1beta1/zz_generated.deepcopy.go

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

0 comments on commit 15805f8

Please sign in to comment.