mirror of
https://github.com/openshift/installer.git
synced 2026-02-05 15:47:14 +01:00
OCPBUGS-62870: installing into GCP Shared VPC with minimal permissions
** Ensure that the feature is backwards compatible for original XPN cases. The new field firewallRulesManagement is an explicit setting of whether the user has the firewall rules or not. In old versions this did not exist but XPN installs did not need firewall rules. Now we will default to checking permissions when no field value is provided. If the rules do not exist, the rules management is set to unmanaged.
This commit is contained in:
committed by
openshift-cherrypick-robot
parent
763d379a9d
commit
69f8b9d3cf
@@ -6315,11 +6315,15 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
firewallRulesManagement:
|
||||
default: Managed
|
||||
description: |-
|
||||
FirewallRulesManagement specifies the management policy for the cluster. Managed indicates that
|
||||
the firewall rules will be created and destroyed by the cluster. Unmanaged indicates that the
|
||||
user should create and destroy the firewall rules.
|
||||
FirewallRulesManagement specifies the management policy for the cluster. "Managed" indicates that
|
||||
the firewall rules will be created and destroyed by the cluster. "Unmanaged" indicates that the
|
||||
user should create and destroy the firewall rules. For Shared VPC installation, if the installer
|
||||
credential doesn't have firewall rules management permissions, the "firewallRulesManagement" settings
|
||||
can be absent or set to "Unmanaged" explicitly. For non-Shared VPC installation, if the installer
|
||||
credential doesn't have firewall rules management permissions, the "firewallRulesManagement" settings
|
||||
must be set to "Unmanaged" explicitly. And in this case, the user needs to pre-configure the VPC network
|
||||
and the firewall rules before the installation.
|
||||
enum:
|
||||
- Managed
|
||||
- Unmanaged
|
||||
|
||||
44
pkg/asset/installconfig/gcp/permissions.go
Normal file
44
pkg/asset/installconfig/gcp/permissions.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
gcptypes "github.com/openshift/installer/pkg/types/gcp"
|
||||
)
|
||||
|
||||
const (
|
||||
// CreateFirewallPermission is the permission to create firewall rules in the google cloud provider.
|
||||
CreateFirewallPermission = "compute.firewalls.create" // required to create GCP firewall rules
|
||||
|
||||
// DeleteFirewallPermission is the permission to delete firewall rules in the google cloud provider.
|
||||
DeleteFirewallPermission = "compute.firewalls.delete"
|
||||
|
||||
// UpdateNetworksPermission is the permission to update networks and the network resources in the google cloud provider.
|
||||
UpdateNetworksPermission = "compute.networks.updatePolicy"
|
||||
)
|
||||
|
||||
// HasPermission determines if the permission exists for the service account in the project.
|
||||
func HasPermission(ctx context.Context, projectID string, permissions []string, endpoint *gcptypes.PSCEndpoint) (bool, error) {
|
||||
client, err := NewClient(ctx, endpoint)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to create client permission check: %w", err)
|
||||
}
|
||||
|
||||
foundPermissions, err := client.GetProjectPermissions(ctx, projectID, permissions)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to find project permissions: %w", err)
|
||||
}
|
||||
|
||||
permissionsValid := true
|
||||
for _, permission := range permissions {
|
||||
if hasPermission := foundPermissions.Has(permission); !hasPermission {
|
||||
logrus.Debugf("permission %s not found", permission)
|
||||
permissionsValid = false
|
||||
}
|
||||
}
|
||||
|
||||
return permissionsValid, nil
|
||||
}
|
||||
@@ -494,6 +494,38 @@ func ValidateForProvisioning(ic *types.InstallConfig) error {
|
||||
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if ic.GCP.FirewallRulesManagement == gcp.UnmanagedFirewallRules && ic.GCP.Network == "" {
|
||||
// this is usually a static check, however it is validated here after the
|
||||
// create install-config process to ensure that the create install-config
|
||||
// does not fail in cases where the firewall rules management is set to
|
||||
// unmanaged when the permissions do not exist.
|
||||
allErrs = append(allErrs, field.Required(
|
||||
field.NewPath("platform").Child("gcp").Child("network"),
|
||||
"a network must be specified when firewall rules are unmanaged"),
|
||||
)
|
||||
} else if ic.GCP.FirewallRulesManagement == gcp.ManagedFirewallRules {
|
||||
projectID := ic.GCP.ProjectID
|
||||
configField := "projectID"
|
||||
if ic.GCP.NetworkProjectID != "" {
|
||||
projectID = ic.GCP.NetworkProjectID
|
||||
configField = "networkProjectID"
|
||||
}
|
||||
|
||||
hasPermissions, err := HasPermission(context.TODO(), projectID, []string{
|
||||
CreateFirewallPermission,
|
||||
DeleteFirewallPermission,
|
||||
UpdateNetworksPermission,
|
||||
}, ic.GCP.Endpoint)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.InternalError(field.NewPath("platform").Child("gcp").Child(configField), err))
|
||||
} else if !hasPermissions {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
field.NewPath("platform").Child("gcp").Child("firewallRulesManagement"),
|
||||
ic.GCP.FirewallRulesManagement,
|
||||
"firewall permissions are required when firewall rules management is set to Managed"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs.ToAggregate()
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
icvsphere "github.com/openshift/installer/pkg/asset/installconfig/vsphere"
|
||||
"github.com/openshift/installer/pkg/types"
|
||||
"github.com/openshift/installer/pkg/types/defaults"
|
||||
"github.com/openshift/installer/pkg/types/gcp"
|
||||
"github.com/openshift/installer/pkg/types/validation"
|
||||
)
|
||||
|
||||
@@ -133,6 +135,33 @@ func (a *InstallConfig) finishGCP() error {
|
||||
}
|
||||
a.Config.Platform.GCP.Endpoint.ClusterUseOnly = &defaultClusterUseOnly
|
||||
}
|
||||
|
||||
project := a.Config.GCP.ProjectID
|
||||
if a.Config.Platform.GCP.NetworkProjectID != "" {
|
||||
project = a.Config.GCP.NetworkProjectID
|
||||
}
|
||||
|
||||
if a.Config.GCP.FirewallRulesManagement == "" {
|
||||
firewallPermissions, err := icgcp.HasPermission(context.TODO(), project, []string{
|
||||
icgcp.CreateFirewallPermission,
|
||||
icgcp.DeleteFirewallPermission,
|
||||
icgcp.UpdateNetworksPermission,
|
||||
}, a.Config.GCP.Endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Config.GCP.FirewallRulesManagement = gcp.ManagedFirewallRules
|
||||
if !firewallPermissions {
|
||||
if a.Config.GCP.NetworkProjectID != "" {
|
||||
logrus.Debugf("missing firewall permissions, setting rule management to Unmanaged")
|
||||
a.Config.GCP.FirewallRulesManagement = gcp.UnmanagedFirewallRules
|
||||
} else {
|
||||
logrus.Warnf("missing firewall permissions, add the permissions or set firewall rules management to Unmanaged and create firewall rules")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,6 @@ func SetPlatformDefaults(p *gcp.Platform) {
|
||||
return
|
||||
}
|
||||
|
||||
if p.FirewallRulesManagement == "" {
|
||||
p.FirewallRulesManagement = gcp.ManagedFirewallRules
|
||||
}
|
||||
|
||||
if gcpDmp := p.DefaultMachinePlatform; gcpDmp != nil {
|
||||
if ek := gcpDmp.EncryptionKey; ek != nil {
|
||||
if kms := ek.KMSKey; kms != nil {
|
||||
|
||||
@@ -121,10 +121,14 @@ type Platform struct {
|
||||
// +optional
|
||||
DNS *DNS `json:"dns,omitempty"`
|
||||
|
||||
// FirewallRulesManagement specifies the management policy for the cluster. Managed indicates that
|
||||
// the firewall rules will be created and destroyed by the cluster. Unmanaged indicates that the
|
||||
// user should create and destroy the firewall rules.
|
||||
// +default="Managed"
|
||||
// FirewallRulesManagement specifies the management policy for the cluster. "Managed" indicates that
|
||||
// the firewall rules will be created and destroyed by the cluster. "Unmanaged" indicates that the
|
||||
// user should create and destroy the firewall rules. For Shared VPC installation, if the installer
|
||||
// credential doesn't have firewall rules management permissions, the "firewallRulesManagement" settings
|
||||
// can be absent or set to "Unmanaged" explicitly. For non-Shared VPC installation, if the installer
|
||||
// credential doesn't have firewall rules management permissions, the "firewallRulesManagement" settings
|
||||
// must be set to "Unmanaged" explicitly. And in this case, the user needs to pre-configure the VPC network
|
||||
// and the firewall rules before the installation.
|
||||
// +optional
|
||||
FirewallRulesManagement FirewallRulesManagementPolicy `json:"firewallRulesManagement,omitempty"`
|
||||
}
|
||||
|
||||
@@ -150,10 +150,6 @@ func ValidatePlatform(p *gcp.Platform, fldPath *field.Path, ic *types.InstallCon
|
||||
if !supportedFirewallRulePolicies.Has(p.FirewallRulesManagement) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("firewallRulesManagement"), p.FirewallRulesManagement, sets.List(supportedFirewallRulePolicies)))
|
||||
}
|
||||
|
||||
if p.FirewallRulesManagement == gcp.UnmanagedFirewallRules && p.Network == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("network"), "a network must be specified when firewall rules are unmanaged"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
|
||||
@@ -232,16 +232,6 @@ func TestValidatePlatform(t *testing.T) {
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "invalid firewall management configuration",
|
||||
platform: &gcp.Platform{
|
||||
UserProvisionedDNS: dns.UserProvisionedDNSEnabled,
|
||||
FirewallRulesManagement: gcp.UnmanagedFirewallRules,
|
||||
Region: "us-east1",
|
||||
ProjectID: "valid-project",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "invalid firewall management",
|
||||
platform: &gcp.Platform{
|
||||
|
||||
Reference in New Issue
Block a user