Add ciphers options for listeners and pools
Added an option to specify the TLS ciphers used by listeners and pools. It is specifed through a string in OpenSSL syntax. Change-Id: Icead9106b06ae7610301a121e51dc5fe1a0e4056 Co-authored-by: Steven Glasford <stevenglasford@gmail.com> Story: 2006627 Task: 37193
This commit is contained in:
parent
1a29983ebc
commit
daae6d1fcd
@ -185,7 +185,9 @@ def create_listener(request, **kwargs):
|
|||||||
timeout_member_connect=data['listener'].get('timeout_member_connect'),
|
timeout_member_connect=data['listener'].get('timeout_member_connect'),
|
||||||
timeout_member_data=data['listener'].get('timeout_member_data'),
|
timeout_member_data=data['listener'].get('timeout_member_data'),
|
||||||
timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'),
|
timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'),
|
||||||
allowed_cidrs=data['listener'].get('allowed_cidrs')
|
allowed_cidrs=data['listener'].get('allowed_cidrs'),
|
||||||
|
# Replace empty string by None (uses default tls cipher string)
|
||||||
|
tls_ciphers=data['listener'].get('tls_ciphers') or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
if data.get('pool'):
|
if data.get('pool'):
|
||||||
@ -252,7 +254,9 @@ def create_pool(request, **kwargs):
|
|||||||
loadbalancer_id=kwargs['loadbalancer_id'],
|
loadbalancer_id=kwargs['loadbalancer_id'],
|
||||||
name=data['pool'].get('name'),
|
name=data['pool'].get('name'),
|
||||||
description=data['pool'].get('description'),
|
description=data['pool'].get('description'),
|
||||||
admin_state_up=data['pool'].get('admin_state_up')
|
admin_state_up=data['pool'].get('admin_state_up'),
|
||||||
|
# Replace empty string by None (uses default tls cipher string)
|
||||||
|
tls_ciphers=data['pool'].get('tls_ciphers') or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
if data.get('members'):
|
if data.get('members'):
|
||||||
@ -458,7 +462,9 @@ def update_listener(request, **kwargs):
|
|||||||
timeout_member_connect=data['listener'].get('timeout_member_connect'),
|
timeout_member_connect=data['listener'].get('timeout_member_connect'),
|
||||||
timeout_member_data=data['listener'].get('timeout_member_data'),
|
timeout_member_data=data['listener'].get('timeout_member_data'),
|
||||||
timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'),
|
timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'),
|
||||||
allowed_cidrs=data['listener'].get('allowed_cidrs')
|
allowed_cidrs=data['listener'].get('allowed_cidrs'),
|
||||||
|
# Replace empty string by None (uses default tls cipher string)
|
||||||
|
tls_ciphers=data['listener'].get('tls_ciphers') or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
if data.get('pool'):
|
if data.get('pool'):
|
||||||
@ -527,7 +533,9 @@ def update_pool(request, **kwargs):
|
|||||||
session_persistence=data['pool'].get('session_persistence'),
|
session_persistence=data['pool'].get('session_persistence'),
|
||||||
name=data['pool'].get('name'),
|
name=data['pool'].get('name'),
|
||||||
description=data['pool'].get('description'),
|
description=data['pool'].get('description'),
|
||||||
admin_state_up=data['pool'].get('admin_state_up')
|
admin_state_up=data['pool'].get('admin_state_up'),
|
||||||
|
# Replace empty string by None (uses default tls cipher string)
|
||||||
|
tls_ciphers=data['pool'].get('tls_ciphers') or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Assemble the lists of member id's to add and remove, if any exist
|
# Assemble the lists of member id's to add and remove, if any exist
|
||||||
|
@ -53,7 +53,8 @@
|
|||||||
'id', 'name', 'description', 'project_id', 'created_at', 'updated_at',
|
'id', 'name', 'description', 'project_id', 'created_at', 'updated_at',
|
||||||
'connection_limit', 'insert_headers', 'default_pool_id',
|
'connection_limit', 'insert_headers', 'default_pool_id',
|
||||||
'timeout_client_data', 'timeout_member_connect',
|
'timeout_client_data', 'timeout_member_connect',
|
||||||
'timeout_member_data', 'timeout_tcp_inspect', 'allowed_cidrs'
|
'timeout_member_data', 'timeout_tcp_inspect', 'allowed_cidrs',
|
||||||
|
'tls_ciphers'
|
||||||
]]">
|
]]">
|
||||||
</hz-resource-property-list>
|
</hz-resource-property-list>
|
||||||
</div>
|
</div>
|
||||||
|
@ -185,7 +185,8 @@
|
|||||||
timeout_member_connect: gettext('Member Connect Timeout'),
|
timeout_member_connect: gettext('Member Connect Timeout'),
|
||||||
timeout_member_data: gettext('Member Data Timeout'),
|
timeout_member_data: gettext('Member Data Timeout'),
|
||||||
timeout_tcp_inspect: gettext('TCP Inspect Timeout'),
|
timeout_tcp_inspect: gettext('TCP Inspect Timeout'),
|
||||||
load_balancers: gettext('Load Balancers')
|
load_balancers: gettext('Load Balancers'),
|
||||||
|
tls_ciphers: gettext('TLS Cipher String')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
item="ctrl.pool"
|
item="ctrl.pool"
|
||||||
property-groups="[[
|
property-groups="[[
|
||||||
'id', 'name', 'description', 'project_id', 'created_at', 'updated_at',
|
'id', 'name', 'description', 'project_id', 'created_at', 'updated_at',
|
||||||
'session_persistence', 'health_monitor_id']]">
|
'session_persistence', 'health_monitor_id', 'tls_ciphers']]">
|
||||||
</hz-resource-property-list>
|
</hz-resource-property-list>
|
||||||
</div>
|
</div>
|
||||||
</uib-tab>
|
</uib-tab>
|
||||||
|
@ -175,7 +175,8 @@
|
|||||||
},
|
},
|
||||||
loadbalancers: gettext('Load Balancers'),
|
loadbalancers: gettext('Load Balancers'),
|
||||||
listeners: gettext('Listeners'),
|
listeners: gettext('Listeners'),
|
||||||
members: gettext('Members')
|
members: gettext('Members'),
|
||||||
|
tls_ciphers: gettext('TLS Cipher String')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
'The connection limit must be a number greater than or equal to -1.'
|
'The connection limit must be a number greater than or equal to -1.'
|
||||||
);
|
);
|
||||||
ctrl.timeoutError = gettext('The timeout must be a number between 0 and 31536000000.');
|
ctrl.timeoutError = gettext('The timeout must be a number between 0 and 31536000000.');
|
||||||
|
ctrl.tls_ciphersError = gettext('The cipher string must conform to OpenSSL syntax.');
|
||||||
|
|
||||||
////////////
|
////////////
|
||||||
|
|
||||||
|
@ -69,3 +69,13 @@
|
|||||||
An empty list means allow from any.
|
An empty list means allow from any.
|
||||||
</translate>
|
</translate>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong translate>TLS Cipher String:</strong>
|
||||||
|
<translate>
|
||||||
|
A string of the allowed ciphers using the OpenSSL syntax. The syntax
|
||||||
|
is a colon separated list of the chiphers, ex.
|
||||||
|
"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
|
||||||
|
Note, don't include quotation marks. An empty string sets the default TLS
|
||||||
|
Cipher String configured in Octavia.
|
||||||
|
</translate>
|
||||||
|
</p>
|
||||||
|
@ -167,6 +167,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row" ng-if="model.spec.listener.protocol === 'TERMINATED_HTTPS'">
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-8 col-md-6">
|
||||||
|
<div class="form-group"
|
||||||
|
ng-class="{ 'has-error': listenerDetailsForm.tls_ciphers.$invalid && listenerDetailsForm.tls_ciphers.$dirty }">
|
||||||
|
<label translate class="control-label" for="tls_ciphers">TLS Cipher String</label>
|
||||||
|
<textarea name="tls_ciphers" id="tls_ciphers" class="form-control"
|
||||||
|
ng-model="model.spec.listener.tls_ciphers" ng-pattern="/^([A-Z0-9_-]+:)*[A-Z0-9_-]+$/">
|
||||||
|
</textarea>
|
||||||
|
<span class="help-block" ng-show="listenerDetailsForm.tls_ciphers.$invalid && listenerDetailsForm.tls_ciphers.$dirty">
|
||||||
|
{$ ::ctrl.tls_ciphersError $}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<h4 translate ng-if="model.spec.listener.protocol === 'HTTP' || model.spec.listener.protocol === 'TERMINATED_HTTPS'">Insert Headers</h4>
|
<h4 translate ng-if="model.spec.listener.protocol === 'HTTP' || model.spec.listener.protocol === 'TERMINATED_HTTPS'">Insert Headers</h4>
|
||||||
|
|
||||||
<div class="row form-group" ng-if="model.spec.listener.protocol === 'HTTP' || model.spec.listener.protocol === 'TERMINATED_HTTPS'">
|
<div class="row form-group" ng-if="model.spec.listener.protocol === 'HTTP' || model.spec.listener.protocol === 'TERMINATED_HTTPS'">
|
||||||
|
@ -170,7 +170,8 @@
|
|||||||
timeout_member_connect: 5000,
|
timeout_member_connect: 5000,
|
||||||
timeout_member_data: 50000,
|
timeout_member_data: 50000,
|
||||||
timeout_tcp_inspect: 0,
|
timeout_tcp_inspect: 0,
|
||||||
allowed_cidrs: null
|
allowed_cidrs: null,
|
||||||
|
tls_ciphers: null
|
||||||
},
|
},
|
||||||
l7policy: {
|
l7policy: {
|
||||||
id: null,
|
id: null,
|
||||||
@ -201,7 +202,8 @@
|
|||||||
type: null,
|
type: null,
|
||||||
cookie_name: null
|
cookie_name: null
|
||||||
},
|
},
|
||||||
admin_state_up: true
|
admin_state_up: true,
|
||||||
|
tls_ciphers: null
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
id: null,
|
id: null,
|
||||||
@ -516,6 +518,7 @@
|
|||||||
if (finalSpec.listener.protocol !== 'TERMINATED_HTTPS') {
|
if (finalSpec.listener.protocol !== 'TERMINATED_HTTPS') {
|
||||||
// Remove certificate containers if not using TERMINATED_HTTPS
|
// Remove certificate containers if not using TERMINATED_HTTPS
|
||||||
delete finalSpec.certificates;
|
delete finalSpec.certificates;
|
||||||
|
delete finalSpec.listener.tls_ciphers;
|
||||||
} else {
|
} else {
|
||||||
var containers = [];
|
var containers = [];
|
||||||
angular.forEach(finalSpec.certificates, function(cert) {
|
angular.forEach(finalSpec.certificates, function(cert) {
|
||||||
@ -803,6 +806,7 @@
|
|||||||
spec.timeout_member_data = listener.timeout_member_data;
|
spec.timeout_member_data = listener.timeout_member_data;
|
||||||
spec.timeout_tcp_inspect = listener.timeout_tcp_inspect;
|
spec.timeout_tcp_inspect = listener.timeout_tcp_inspect;
|
||||||
spec.allowed_cidrs = listener.allowed_cidrs;
|
spec.allowed_cidrs = listener.allowed_cidrs;
|
||||||
|
spec.tls_ciphers = listener.tls_ciphers;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setL7PolicySpec(l7policy) {
|
function setL7PolicySpec(l7policy) {
|
||||||
@ -837,6 +841,7 @@
|
|||||||
spec.lb_algorithm = pool.lb_algorithm;
|
spec.lb_algorithm = pool.lb_algorithm;
|
||||||
spec.admin_state_up = pool.admin_state_up;
|
spec.admin_state_up = pool.admin_state_up;
|
||||||
spec.session_persistence = pool.session_persistence;
|
spec.session_persistence = pool.session_persistence;
|
||||||
|
spec.tls_ciphers = pool.tls_ciphers;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMembersSpec(membersList) {
|
function setMembersSpec(membersList) {
|
||||||
|
@ -1298,10 +1298,10 @@
|
|||||||
it('has the right number of properties', function() {
|
it('has the right number of properties', function() {
|
||||||
expect(Object.keys(model.spec).length).toBe(11);
|
expect(Object.keys(model.spec).length).toBe(11);
|
||||||
expect(Object.keys(model.spec.loadbalancer).length).toBe(7);
|
expect(Object.keys(model.spec.loadbalancer).length).toBe(7);
|
||||||
expect(Object.keys(model.spec.listener).length).toBe(15);
|
expect(Object.keys(model.spec.listener).length).toBe(16);
|
||||||
expect(Object.keys(model.spec.l7policy).length).toBe(8);
|
expect(Object.keys(model.spec.l7policy).length).toBe(8);
|
||||||
expect(Object.keys(model.spec.l7rule).length).toBe(7);
|
expect(Object.keys(model.spec.l7rule).length).toBe(7);
|
||||||
expect(Object.keys(model.spec.pool).length).toBe(7);
|
expect(Object.keys(model.spec.pool).length).toBe(8);
|
||||||
expect(Object.keys(model.spec.monitor).length).toBe(11);
|
expect(Object.keys(model.spec.monitor).length).toBe(11);
|
||||||
expect(model.spec.members).toEqual([]);
|
expect(model.spec.members).toEqual([]);
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('horizon.dashboard.project.lbaasv2')
|
||||||
|
.controller('PoolDetailsController', PoolDetailsController);
|
||||||
|
|
||||||
|
PoolDetailsController.$inject = [
|
||||||
|
'$scope',
|
||||||
|
'horizon.framework.util.i18n.gettext'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc controller
|
||||||
|
* @name PoolDetailsController
|
||||||
|
* @description
|
||||||
|
* The `PoolDetailsController` controller provides functions for
|
||||||
|
* configuring the pool details step of the LBaaS wizard.
|
||||||
|
* @param $scope The angular scope object.
|
||||||
|
* @param gettext The horizon gettext function for translation.
|
||||||
|
* @returns undefined
|
||||||
|
*/
|
||||||
|
|
||||||
|
function PoolDetailsController($scope, gettext) {
|
||||||
|
var ctrl = this;
|
||||||
|
|
||||||
|
// Error text for invalid fields
|
||||||
|
ctrl.tls_ciphersError = gettext('The cipher string must conform to OpenSSL syntax.');
|
||||||
|
}
|
||||||
|
})();
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('Pool Details Step', function() {
|
||||||
|
|
||||||
|
beforeEach(module('horizon.framework.util.i18n'));
|
||||||
|
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||||
|
|
||||||
|
describe('PoolDetailsController', function() {
|
||||||
|
var ctrl, scope;
|
||||||
|
|
||||||
|
beforeEach(inject(function($controller, $rootScope) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
ctrl = $controller('PoolDetailsController', {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should define error messages for invalid fields', function() {
|
||||||
|
expect(ctrl.tls_ciphersError).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
@ -42,3 +42,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong translate>TLS Cipher String:</strong>
|
||||||
|
<translate>
|
||||||
|
A string of the allowed ciphers using the OpenSSL syntax. The syntax
|
||||||
|
is a colon separated list of the chiphers, ex.
|
||||||
|
"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
|
||||||
|
Note, don't include quotation marks. An empty string sets the default TLS
|
||||||
|
Cipher String configured in Octavia.
|
||||||
|
</translate>
|
||||||
|
</p>
|
@ -1,4 +1,4 @@
|
|||||||
<div>
|
<div ng-controller="PoolDetailsController as ctrl">
|
||||||
<p translate>Provide the details for the pool.</p>
|
<p translate>Provide the details for the pool.</p>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -84,6 +84,23 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-8 col-md-6">
|
||||||
|
<div class="form-group"
|
||||||
|
ng-class="{ 'has-error': poolDetailsForm.tls_ciphers.$invalid && poolDetailsForm.tls_ciphers.$dirty }">
|
||||||
|
<label translate class="control-label" for="tls_ciphers">TLS Cipher String</label>
|
||||||
|
<textarea name="tls_ciphers" id="tls_ciphers" class="form-control"
|
||||||
|
ng-model="model.spec.pool.tls_ciphers" ng-pattern="/^([A-Z0-9_-]+:)*[A-Z0-9_-]+$/">
|
||||||
|
</textarea>
|
||||||
|
<span class="help-block" ng-show="poolDetailsForm.tls_ciphers.$invalid && poolDetailsForm.tls_ciphers.$dirty">
|
||||||
|
{$ ::ctrl.tls_ciphersError $}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-xs-12 col-sm-8 col-md-6">
|
<div class="col-xs-12 col-sm-8 col-md-6">
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added option to specify TLS ciphers for listeners and pools.
|
||||||
|
The ciphers are represented in OpenSSL syntax.
|
Loading…
Reference in New Issue
Block a user