From 207503080df22fb0736da8af434600fee8ba9603 Mon Sep 17 00:00:00 2001 From: Dale Smith Date: Mon, 13 May 2024 15:53:02 +1200 Subject: [PATCH] Change floating_ip to use master_lb_floating_ip_enabled. * Replace 'floating_ip_enabled' with 'master_lb_floating_ip_enabled', as the former implies floating ip on all nodes in addition to a Floating IP on the API loadbalancer. * Add 'api_master_lb_allowed_cidrs' so limitations can be placed on K8s API loadbalancer. Change-Id: I18bf64be9d9ddb4ee043cfba37bffe8e82f33d0d --- .../clusters/create/create.service.js | 5 +- .../workflow/cluster-template.controller.js | 11 +-- .../cluster-template.controller.spec.js | 17 +++-- .../clusters/workflow/network.help.html | 15 +++- .../clusters/workflow/workflow.service.js | 70 +++++++++++++++---- .../lb_floating_ip-ca6039444f88a968.yaml | 8 +++ 6 files changed, 98 insertions(+), 28 deletions(-) create mode 100644 releasenotes/notes/lb_floating_ip-ca6039444f88a968.yaml diff --git a/magnum_ui/static/dashboard/container-infra/clusters/create/create.service.js b/magnum_ui/static/dashboard/container-infra/clusters/create/create.service.js index 3ff524ba..c30fa7a3 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/create/create.service.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/create/create.service.js @@ -99,7 +99,6 @@ name: model.name, cluster_template_id: model.cluster_template_id, keypair: model.keypair, - floating_ip_enabled: model.floating_ip_enabled, labels: requestLabels, master_lb_enabled: model.master_lb_enabled }; @@ -126,6 +125,10 @@ requestLabels.availability_zone = model.availability_zone; requestLabels.auto_scaling_enabled = model.auto_scaling_enabled; requestLabels.auto_healing_enabled = model.auto_healing_enabled; + requestLabels.master_lb_floating_ip_enabled = model.master_lb_floating_ip_enabled; + if (model.api_master_lb_allowed_cidrs !== '') { + requestLabels.api_master_lb_allowed_cidrs = model.api_master_lb_allowed_cidrs; + } if (model.auto_scaling_enabled) { requestLabels.min_node_count = model.min_node_count; diff --git a/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.js b/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.js index 674c4f87..ada0ac5a 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.js @@ -85,10 +85,7 @@ setResponseAsDefaultIfUnset('master_flavor_id', 'master_flavor_id'); setResponseAsDefaultIfUnset('node_count', 'node_count'); setResponseAsDefaultIfUnset('flavor_id', 'flavor_id'); - - if (template.floating_ip_enabled !== null) { - $scope.model.floating_ip_enabled = template.floating_ip_enabled; - } + setResponseAsDefaultIfUnset('master_lb_enabled', 'master_lb_enabled'); if (!template.labels) { return; } @@ -97,6 +94,12 @@ // If a template label exists as a field on the form -> Set it as a default setLabelResponseAsDefault('auto_scaling_enabled', 'auto_scaling_enabled', true); setLabelResponseAsDefault('auto_healing_enabled', 'auto_healing_enabled', true); + setLabelResponseAsDefault( + 'master_lb_floating_ip_enabled', + 'master_lb_floating_ip_enabled', + true); + // Forcibly clear allowed cidr values on template load. Otherwise this value becomes nil. + $scope.model.api_master_lb_allowed_cidrs = MODEL_DEFAULTS.api_master_lb_allowed_cidrs; // Set default `ingress_controller` based on its label if (template.labels.ingress_controller !== null && diff --git a/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.spec.js b/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.spec.js index 28ebde5b..3a5e987c 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.spec.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/workflow/cluster-template.controller.spec.js @@ -204,12 +204,14 @@ it('should always override some model properties by values from ' + 'retrieved cluster template', function() { - $scope.model.floating_ip_enabled = !MODEL_DEFAULTS.floating_ip_enabled; - templateResponse.floating_ip_enabled = !$scope.model.floating_ip_enabled; - $scope.model.cluster_template_id = '99'; // Triggers bussines logic revalidation + $scope.model.master_lb_floating_ip_enabled = !MODEL_DEFAULTS.master_lb_floating_ip_enabled; + templateResponse.master_lb_floating_ip_enabled = !$scope.model.master_lb_floating_ip_enabled; + $scope.model.cluster_template_id = '99'; // Triggers business logic revalidation $scope.$apply(); - expect($scope.model.floating_ip_enabled).toBe(templateResponse.floating_ip_enabled); + expect($scope.model.master_lb_floating_ip_enabled).toBe( + templateResponse.master_lb_floating_ip_enabled + ); }); it('should always override some model\'s properties by values from ' + @@ -220,11 +222,16 @@ templateResponse.labels.auto_scaling_enabled = 'true'; model.auto_healing_enabled = true; templateResponse.labels.auto_healing_enabled = 'false'; - model.cluster_template_id = '99'; // Triggers bussines logic revalidation + model.api_master_lb_allowed_cidrs = "192.168.67.0/24"; + templateResponse.labels.api_master_lb_allowed_cidrs = "10.0.0.1/16"; + model.cluster_template_id = '99'; // Triggers business logic revalidation $scope.$apply(); expect(model.auto_scaling_enabled).toBe(true); expect(model.auto_healing_enabled).toBe(false); + expect($scope.model.api_master_lb_allowed_cidrs).toBe( + MODEL_DEFAULTS.api_master_lb_allowed_cidrs + ); }); it('should not fail if the cluster template response is empty', function() { diff --git a/magnum_ui/static/dashboard/container-infra/clusters/workflow/network.help.html b/magnum_ui/static/dashboard/container-infra/clusters/workflow/network.help.html index e73ea502..450f9df9 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/workflow/network.help.html +++ b/magnum_ui/static/dashboard/container-infra/clusters/workflow/network.help.html @@ -1,4 +1,13 @@ -

Cluster API

+

Network

-

Making the Kubernetes API accessible from the private network only is the most secure option (the default), but access will be limited to compute instances on the same private network or a VPN to that network.

-

Making the Kubernetes API accessible from anywhere on the public internet is convenient, but may represent a security risk. [When selecting this option, it is recommended to limit access to a trusted IP address range.]

\ No newline at end of file +

You can choose to create a new network for this cluster, or use an existing network. If you use an existing, it needs to have a subnet and router with a gateway on the external network. You may also need to take care not to conflict with CIDRs in use by the Kubernetes pod and service network.

+ + +

API Loadbalancer: Floating IP

+ +

Making the Kubernetes API accessible from your private network only is the most secure option (the default), but access will be limited to compute instances on the same private network or a VPN to that network.

+

Making the Kubernetes API accessible from the public internet with a floating IP is convenient, but may represent a security risk. When selecting this option, it is recommended to set Allowed CIDRs to limit access to a trusted IP address range.

+ + +

API Loadbalancer: Allowed CIDRs

+

If this field is left empty, the API Loadbalancer will accept connections from any address. When set to one or more CIDR then only those, plus the internal network, are permitted access to the Kubernetes API Loadbalancer.

diff --git a/magnum_ui/static/dashboard/container-infra/clusters/workflow/workflow.service.js b/magnum_ui/static/dashboard/container-infra/clusters/workflow/workflow.service.js index ddcdabf1..a128e515 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/workflow/workflow.service.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/workflow/workflow.service.js @@ -44,6 +44,9 @@ // comma-separated key=value with optional space after comma var REGEXP_KEY_VALUE = /^(\w+=[^,]+,?\s?)+$/; + // Comma-separated CIDR list. Allows lots of variation to include v4 and v6. + var REGEXP_CIDR_LIST = /^[a-f0-9\.:]+\/[0-9]+(,\s?[a-f0-9\.:]+\/[0-9]+)*$/; + // Object name, must start with alphabetical character. var REGEXP_CLUSTER_NAME = /^[a-zA-Z][a-zA-Z0-9_\-\.]*$/; @@ -109,7 +112,8 @@ 'create_network': { type: 'boolean' }, 'fixed_network': { type: 'string' }, 'fixed_subnet': { type: 'string' }, - 'floating_ip_enabled': { type: 'boolean' }, + 'master_lb_floating_ip_enabled': { type: 'boolean' }, + 'api_master_lb_allowed_cidrs': { type: 'string' }, 'ingress_controller': { type: 'object' }, 'auto_healing_enabled': { type: 'boolean' }, @@ -359,11 +363,6 @@ type: 'fieldset', title: gettext('Network'), items: [ - { - key: 'master_lb_enabled', - type: 'checkbox', - title: gettext('Enable Load Balancer for Master Nodes') - }, { key: 'create_network', title: gettext('Create New Network'), @@ -398,25 +397,65 @@ }, { type: 'fieldset', - title: gettext('Network Access Control'), + title: gettext('Kubernetes API Loadbalancer'), items: [ { - key: 'floating_ip_enabled', + key: 'master_lb_enabled', + type: 'checkbox', + title: gettext('Enable Load Balancer for Kubernetes API'), + onChange: function(value) { + if (value) { + model.master_count = MODEL_DEFAULTS.master_count; + // Reset values to defaults. They are null after being disabled. + model.master_lb_floating_ip_enabled = + MODEL_DEFAULTS.master_lb_floating_ip_enabled; + model.api_master_lb_allowed_cidrs = + MODEL_DEFAULTS.api_master_lb_allowed_cidrs; + } else { + // Without master_lb_enabled, we can only support + // a single master node. + model.master_count = 1; + } + model.isSingleMasterNode = !value; + } + }, + { + key: 'master_lb_floating_ip_enabled', // formerly floating_ip_enabled type: 'select', - title: gettext('Cluster API'), + title: gettext('Floating IP'), titleMap: [ {value: false, name: gettext('Accessible on private network only')}, - {value: true, name: gettext('Accessible on the public internet')} - ] + {value: true, name: gettext('Accessible with public floating IP')} + ], + condition: 'model.master_lb_enabled === true' }, - // Warning message for the Cluster API + { + key: 'api_master_lb_allowed_cidrs', + type: 'text', + title: gettext('Allowed CIDRs'), + validationMessage: { + invalidFormat: gettext('Invalid format. Must be a comma-separated ' + + 'CIDR string: 192.168.1.5/32,10.0.0.1/24') + }, + $validators: { + invalidFormat: function(cidrString) { + return cidrString === '' || REGEXP_CIDR_LIST.test(cidrString); + } + }, + condition: 'model.master_lb_enabled === true', + }, + // Warning message when Kubernetes API has a Floating IP { type: 'template', template: '
' + ' ' + - gettext('It is generally not recommended to give public access.') + + gettext('A public floating IP will mean the Kubernetes API is ' + + 'publically routable on the internet. It is generally not ' + + 'recommended to give public access to the Kubernetes API. ' + + 'Consider limiting the access using the Allowed CIDRs ' + + 'section.') + '
', - condition: 'model.floating_ip_enabled == true' + condition: 'model.master_lb_floating_ip_enabled == true' } ] }, @@ -538,7 +577,8 @@ create_network: true, fixed_network: '', fixed_subnet: '', - floating_ip_enabled: false, + master_lb_floating_ip_enabled: false, + api_master_lb_allowed_cidrs: '', ingress_controller: '', auto_healing_enabled: true, diff --git a/releasenotes/notes/lb_floating_ip-ca6039444f88a968.yaml b/releasenotes/notes/lb_floating_ip-ca6039444f88a968.yaml new file mode 100644 index 00000000..a31add3c --- /dev/null +++ b/releasenotes/notes/lb_floating_ip-ca6039444f88a968.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + The Create Cluster workflow option `floating_ip_enabled` has been replaced + with `master_lb_floating_ip_enabled` label as the former added floating + IP's to all nodes, whereas the replacement only adds a floating IP to the + K8s API loadbalancer itself. The field `floating_ip_enabled` has not + changed behaviour and can still be used via the CLI.