Add rbac support for octavia service apis

Co-Authored-By: Michael Johnson <johnsomor@gmail.com>
Change-Id: I6e27a5e81d9075c2ab8622c617409f0f2747f11e
This commit is contained in:
Jacky Hu 2018-03-07 11:59:34 +08:00
parent 5b7326405a
commit d90c3bf03a
43 changed files with 223 additions and 80 deletions

3
.gitignore vendored
View File

@ -61,3 +61,6 @@ ChangeLog
.*.swp
.*sw?
.ropeproject/
# Conf
octavia_dashboard/conf

View File

@ -37,12 +37,28 @@ Howto
2. Copy ``_1482_project_load_balancer_panel.py`` in
``octavia_dashboard/enabled`` directory
to ``openstack_dashboard/local/enabled``.
to ``openstack_dashboard/local/enabled``::
3. (Optional) Copy the policy file into horizon's policy files folder, and
add this config ``POLICY_FILES``::
$ cp -a \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_*.py \
${HORIZON_DIR}/openstack_dashboard/local/enabled/
'octavia': 'octavia_policy.json',
3. (Optional) Generate the policy file and copy into horizon's policy files
folder, and copy ``_1499_load_balancer_settings.py`` in
``octavia_dashboard/local_settings.d`` directory
to ``openstack_dashboard/local/local_settings.d``::
$ oslopolicy-policy-generator \
--config-file \
${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf \
--output-file \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml
$ cp -a \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml \
${HORIZON_DIR}/openstack_dashboard/conf/
$ cp -a \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_*.py \
${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/
4. Django has a compressor feature that performs many enhancements for the
delivery of static files. If the compressor feature is enabled in your

View File

@ -1,10 +1,15 @@
function octavia_dashboard_install {
setup_develop $OCTAVIA_DASHBOARD_DIR
setup_develop ${OCTAVIA_DASHBOARD_DIR}
}
function octavia_dashboard_configure {
cp $OCTAVIA_DASHBOARD_ENABLE_FILE_PATH \
$HORIZON_DIR/openstack_dashboard/local/enabled/
cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_project_load_balancer_panel.py ${HORIZON_DIR}/openstack_dashboard/local/enabled/
cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/
oslopolicy-policy-generator --config-file ${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf --output-file ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml
cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml ${HORIZON_DIR}/openstack_dashboard/conf/
if [[ -d ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/locale ]]; then
(cd ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard; DJANGO_SETTINGS_MODULE=openstack_dashboard.settings python ../manage.py compilemessages)
fi
}
if is_service_enabled horizon && is_service_enabled o-api; then
@ -16,20 +21,18 @@ if is_service_enabled horizon && is_service_enabled o-api; then
echo_summary "Configuring octavia-dashboard"
octavia_dashboard_configure
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
# Initialize and start the Octavia dashboard service
echo_summary "Initializing octavia-dashboard"
fi
fi
if [[ "$1" == "unstack" ]]; then
# Shut down Octavia dashboard services
:
fi
fi
if [[ "$1" == "clean" ]]; then
if [[ "$1" == "unstack" ]]; then
:
fi
if [[ "$1" == "clean" ]]; then
# Remove state and transient data
# Remember clean.sh first calls unstack.sh
# Remove octavia-dashboard enabled file and pyc
rm -f "$HORIZON_DIR"/openstack_dashboard/local/enabled/"$OCTAVIA_DASHBOARD_ENABLE_FILE_NAME"*
rm -f ${HORIZON_DIR}/openstack_dashboard/local/enabled/_1482_project_load_balancer_panel.py*
rm -f ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/_1499_load_balancer_settings.py*
rm -f ${HORIZON_DIR}/openstack_dashboard/conf/octavia_policy.yaml
fi
fi

View File

@ -1,5 +1 @@
OCTAVIA_DASHBOARD_DIR=$DEST/octavia-dashboard
OCTAVIA_DASHBOARD_ENABLE_FILE_NAME=_1482_project_load_balancer_panel.py
OCTAVIA_DASHBOARD_ENABLE_FILE_PATH=$OCTAVIA_DASHBOARD_DIR/octavia_dashboard/enabled/$OCTAVIA_DASHBOARD_ENABLE_FILE_NAME

View File

@ -109,7 +109,6 @@ bug_project = '909'
bug_tag = 'docs'
# TODO(mordred) We should extract this into a sphinx plugin
def run_apidoc(_):
cur_dir = os.path.abspath(os.path.dirname(__file__))
@ -128,6 +127,8 @@ def run_apidoc(_):
'octavia_dashboard/enabled',
'octavia_dashboard/locale',
'octavia_dashboard/static',
'octavia_dashboard/conf',
'octavia_dashboard/local_settings.d',
'octavia_dashboard/post_install.sh',
'octavia_dashboard/karma.conf.js'
])

View File

@ -0,0 +1,22 @@
# Copyright 2018 Walmart.
# 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.
# This file is to be included for configuring application which relates
# to load-balancer(Octavia) functions.
from django.conf import settings
settings.POLICY_FILES.update({
'load-balancer': 'octavia_policy.yaml',
})

View File

@ -54,7 +54,9 @@
});
function allowed() {
return policy.ifAllowed({ rules: [['neutron', 'create_health_monitor']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:post']]
});
}
function handle(response) {

View File

@ -31,7 +31,11 @@
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed)
.toHaveBeenCalledWith({rules: [['neutron', 'create_health_monitor']]});
.toHaveBeenCalledWith({
rules: [[
'load-balancer', 'os_load-balancer_api:healthmonitor:post'
]]
});
});
it('should handle the action result properly', function() {

View File

@ -67,9 +67,9 @@
//////////////
function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'delete_health_monitor']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:delete']]
});
}
function perform(items, scope) {

View File

@ -55,7 +55,9 @@
});
function allowed(/*healthmonitor*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_health_monitor']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:put']]
});
}
function handle(response) {

View File

@ -31,7 +31,11 @@
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed)
.toHaveBeenCalledWith({rules: [['neutron', 'update_health_monitor']]});
.toHaveBeenCalledWith({
rules: [[
'load-balancer', 'os_load-balancer_api:healthmonitor:put'
]]
});
});
it('should handle the action result properly', function() {

View File

@ -61,7 +61,7 @@
function allowed() {
return $q.all([
policy.ifAllowed({ rules: [['neutron', 'create_l7policy']] })
policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7policy:post']] })
]);
}

View File

@ -67,9 +67,9 @@
//////////////
function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'delete_l7policy']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:l7policy:delete']]
});
}
function perform(items, scope) {

View File

@ -56,7 +56,9 @@
});
function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_l7policy']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:l7policy:put']]
});
}
function handle(response) {

View File

@ -43,7 +43,7 @@
it('should check policy to allow editing a l7policy', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_l7policy']]});
expect(policy.ifAllowed).toHaveBeenCalled();
});
it('should handle the action result properly', function() {

View File

@ -61,7 +61,7 @@
function allowed() {
return $q.all([
policy.ifAllowed({ rules: [['neutron', 'create_l7rule']] })
policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7rule:post']] })
]);
}

View File

@ -67,9 +67,9 @@
//////////////
function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'delete_l7rule']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:l7rule:delete']]
});
}
function perform(items, scope) {

View File

@ -56,7 +56,9 @@
});
function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_l7rule']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:l7rule:put']]
});
}
function handle(response) {

View File

@ -43,7 +43,7 @@
it('should check policy to allow editing a l7rule', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_l7rule']]});
expect(policy.ifAllowed).toHaveBeenCalled();
});
it('should handle the action result properly', function() {

View File

@ -56,7 +56,9 @@
});
function allowed() {
return policy.ifAllowed({ rules: [['neutron', 'create_listener']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:listener:post']]
});
}
function handle(response) {

View File

@ -43,7 +43,13 @@
it('should check policy to allow creating a listener', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'create_listener']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:listener:post'
]]
}
);
});
it('should handle the action result properly', function() {

View File

@ -156,7 +156,9 @@
}
function allowed() {
return policy.ifAllowed({ rules: [['neutron', 'delete_listener']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:listener:delete']]
});
}
function deleteItem(id) {

View File

@ -24,7 +24,13 @@
spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item);
$scope.$apply();
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'delete_listener']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:listener:delete'
]]
}
);
return allowed;
}

View File

@ -56,7 +56,9 @@
});
function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_listener']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:listener:put']]
});
}
function handle(response) {

View File

@ -43,7 +43,13 @@
it('should check policy to allow editing a listener', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_listener']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:listener:put'
]]
}
);
});
it('should handle the action result properly', function() {

View File

@ -57,9 +57,9 @@
});
function allowed() {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'create_loadbalancer']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:post']]
});
}
function handle(response) {

View File

@ -44,7 +44,13 @@
it('should check policy to allow creating a load balancer', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'create_loadbalancer']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:loadbalancer:post'
]]
}
);
});
it('should handle the action result properly', function() {

View File

@ -124,9 +124,9 @@
}
function allowed() {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'delete_loadbalancer']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:delete']]
});
}
function canBeDeleted(item) {

View File

@ -24,7 +24,13 @@
spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item);
$scope.$apply();
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'delete_loadbalancer']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:loadbalancer:delete'
]]
}
);
return allowed;
}

View File

@ -62,9 +62,9 @@
///////////////
function allowed() {
// This rule is made up and should therefore always pass. At some point there will
// likely be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'update_loadbalancer']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:put']]
});
}
function handle(response) {

View File

@ -24,7 +24,13 @@
spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item);
scope.$apply();
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_loadbalancer']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:loadbalancer:put'
]]
}
);
return allowed;
}

View File

@ -65,9 +65,9 @@
//////////////
function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'pool_member_delete']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:member:delete']]
});
}
function perform(items, scope) {

View File

@ -71,9 +71,9 @@
////////////
function allowed(/*item*/) {
// This rule is made up and should therefore always pass. At some point there will
// likely be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'pool_member_update']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:member:put']]
});
}
/**

View File

@ -32,7 +32,13 @@
function allowed(item) {
spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'pool_member_update']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:member:put'
]]
}
);
return allowed;
}

View File

@ -57,7 +57,9 @@
});
function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_member_list']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:put']]
});
}
function handle(response) {

View File

@ -46,7 +46,13 @@
it('should check policy to allow updating member list', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_member_list']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:pool:put'
]]
}
);
});
it('should handle the action result properly', function() {

View File

@ -62,7 +62,9 @@
function allowed() {
return $q.all([
policy.ifAllowed({ rules: [['neutron', 'create_pool']] })
policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:post']]
})
]);
}

View File

@ -68,9 +68,9 @@
//////////////
function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there
// will be a valid rule similar to this that we will want to use.
return policy.ifAllowed({ rules: [['neutron', 'delete_pool']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:delete']]
});
}
function perform(items, scope) {

View File

@ -57,7 +57,9 @@
});
function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_pool']] });
return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:put']]
});
}
function handle(response) {

View File

@ -44,7 +44,13 @@
it('should check policy to allow editing a pool', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_pool']]});
expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:pool:put'
]]
}
);
});
it('should handle the action result properly', function() {

View File

@ -0,0 +1,18 @@
---
features:
- |
Adds RBAC support to the dashboard panels.
upgrade:
- |
To enable RBAC support in the Octavia dashboard you need to install the
generated octavia_dashboard/conf/octavia_policy.yaml file into your
horizon openstack_dashboard/conf/ directory and also
copy octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py
file into your horizon openstack_dashboard/local/local_settings.d/
directory.
security:
- |
RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC
in the dashboard or not, the API RBAC will still be in effect. Enabling
RBAC in the dashboard will enforce the policies in the dashboard before
the API call is made.

View File

@ -38,6 +38,8 @@ autodoc_tree_excludes =
octavia_dashboard/enabled
octavia_dashboard/locale
octavia_dashboard/static
octavia_dashboard/conf
octavia_dashboard/local_settings.d
octavia_dashboard/post_install.sh
octavia_dashboard/karma.conf.js
autodoc_index_modules = False