Andrew Bogott has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/332899 )
Change subject: Keystone hooks: Set up default security groups for new projects. ...................................................................... Keystone hooks: Set up default security groups for new projects. Nova sort of supports this, but it doesn't handle the project-wide groups correctly. Wikitech sort of handles this, but has a race. Bug: T136871 Change-Id: I185651527faf0a44814a1acf3eea2ba5b64ad6bc --- M modules/openstack/files/liberty/keystone/wmfkeystonehooks/wmfkeystonehooks.py M modules/openstack/files/mitaka/keystone/wmfkeystonehooks/wmfkeystonehooks.py M modules/openstack/templates/liberty/keystone/keystone.conf.erb M modules/openstack/templates/mitaka/keystone/keystone.conf.erb 4 files changed, 185 insertions(+), 34 deletions(-) Approvals: Andrew Bogott: Looks good to me, approved jenkins-bot: Verified diff --git a/modules/openstack/files/liberty/keystone/wmfkeystonehooks/wmfkeystonehooks.py b/modules/openstack/files/liberty/keystone/wmfkeystonehooks/wmfkeystonehooks.py index 70027ec..0456a9e 100644 --- a/modules/openstack/files/liberty/keystone/wmfkeystonehooks/wmfkeystonehooks.py +++ b/modules/openstack/files/liberty/keystone/wmfkeystonehooks/wmfkeystonehooks.py @@ -13,8 +13,12 @@ # License for the specific language governing permissions and limitations # under the License. +from keystoneclient.auth.identity import generic +from keystoneclient import session as keystone_session from keystone.common import dependency from keystone import exception +from novaclient import client as nova_client +from novaclient import exceptions from oslo_log import log as logging from oslo_config import cfg @@ -36,6 +40,12 @@ cfg.StrOpt('admin_user', default='novaadmin', help='Admin user to add to all new projects'), + cfg.StrOpt('admin_pass', + default='', + help='Admin password, used to authenticate with other services'), + cfg.StrOpt('auth_url', + default='', + help='Keystone URL, used to authenticate with other services'), cfg.StrOpt('observer_user', default='novaobserver', help='Observer user to add to all new projects'), @@ -48,10 +58,10 @@ cfg.StrOpt('admin_role_name', default='projectadmin', help='Name of project-local admin role'), - cfg.MultiStrOpt('wmf_keystone_eventtype_whitelist', + cfg.MultiStrOpt('eventtype_whitelist', default=['identity.project.deleted', 'identity.project.created'], help='Event types to always handle.'), - cfg.MultiStrOpt('wmf_keystone_eventtype_blacklist', + cfg.MultiStrOpt('eventtype_blacklist', default=[], help='Event types to always ignore.' 'In the event of a conflict, ' @@ -60,7 +70,7 @@ CONF = cfg.CONF -CONF.register_opts(wmfkeystone_opts) +CONF.register_opts(wmfkeystone_opts, group='wmfhooks') @dependency.requires('assignment_api', 'resource_api', 'role_api') @@ -82,25 +92,95 @@ # Make a dict to relate role names to ids for role in rolelist: roledict[role['name']] = role['id'] - if CONF.observer_role_name not in roledict.keys(): - LOG.error("Failed to find id for role %s" % CONF.observer_role_name) + if CONF.wmfhooks.observer_role_name not in roledict.keys(): + LOG.error("Failed to find id for role %s" % CONF.wmfhooks.observer_role_name) raise exception.NotImplemented() - if CONF.admin_role_name not in roledict.keys(): - LOG.error("Failed to find id for role %s" % CONF.admin_role_name) + if CONF.wmfhooks.admin_role_name not in roledict.keys(): + LOG.error("Failed to find id for role %s" % CONF.wmfhooks.admin_role_name) raise exception.NotImplemented() - if CONF.user_role_name not in roledict.keys(): - LOG.error("Failed to find id for role %s" % CONF.user_role_name) + if CONF.wmfhooks.user_role_name not in roledict.keys(): + LOG.error("Failed to find id for role %s" % CONF.wmfhooks.user_role_name) raise exception.NotImplemented() - self.assignment_api.add_role_to_user_and_project(CONF.admin_user, + self.assignment_api.add_role_to_user_and_project(CONF.wmfhooks.admin_user, project_id, - roledict[CONF.admin_role_name]) - self.assignment_api.add_role_to_user_and_project(CONF.admin_user, + roledict[CONF.wmfhooks.admin_role_name]) + self.assignment_api.add_role_to_user_and_project(CONF.wmfhooks.admin_user, project_id, - roledict[CONF.user_role_name]) - self.assignment_api.add_role_to_user_and_project(CONF.observer_user, + roledict[CONF.wmfhooks.user_role_name]) + self.assignment_api.add_role_to_user_and_project(CONF.wmfhooks.observer_user, project_id, - roledict[CONF.observer_role_name]) + roledict[CONF.wmfhooks.observer_role_name]) + + # Use the nova api to set up security groups for the new project + auth = generic.Password( + auth_url=CONF.wmfhooks.auth_url, + username=CONF.wmfhooks.admin_user, + password=CONF.wmfhooks.admin_pass, + user_domain_name='Default', + project_domain_name='Default', + project_name=project_id) + session = keystone_session.Session(auth=auth) + client = nova_client.Client('2', session=session) + allgroups = client.security_groups.list() + defaultgroup = filter(lambda group: group.name == 'default', allgroups) + if defaultgroup: + groupid = defaultgroup[0].id + try: + client.security_group_rules.create(groupid, + ip_protocol='icmp', + from_port='-1', + to_port='-1', + cidr='0.0.0.0/0') + except (exceptions.ClientException): + LOG.warning("icmp security rule already exists.") + try: + client.security_group_rules.create(groupid, + ip_protocol='tcp', + from_port='22', + to_port='22', + cidr='10.0.0.0/8') + except (exceptions.ClientException): + LOG.warning("Port 22 security rule already exists.") + try: + client.security_group_rules.create(groupid, + ip_protocol='tcp', + from_port='5666', + to_port='5666', + cidr='10.0.0.0/8') + except (exceptions.ClientException): + LOG.warning("Port 5666 security rule already exists.") + try: + client.security_group_rules.create(groupid, + ip_protocol='tcp', + from_port='1', + to_port='65535', + cidr='', + group_id=groupid) + except (exceptions.ClientException): + LOG.warning("Project security rule for TCP already exists.") + + try: + client.security_group_rules.create(groupid, + ip_protocol='udp', + from_port='1', + to_port='65535', + cidr='', + group_id=groupid) + except (exceptions.ClientException): + LOG.warning("Project security rule for UDP already exists.") + + try: + client.security_group_rules.create(groupid, + ip_protocol='icmp', + from_port='1', + to_port='65535', + cidr='', + group_id=groupid) + except (exceptions.ClientException): + LOG.warning("Project security rule for ICMP already exists.") + else: + LOG.warning("Failed to find default security group in new project.") def notify(self, context, message, priority, retry=False): event_type = message.get('event_type') @@ -112,9 +192,9 @@ self._on_project_create(message['payload']['resource_info']) # Eventually this will be used to update project resource pages: - if event_type in CONF.wmf_keystone_eventtype_blacklist: + if event_type in CONF.wmfhooks.eventtype_blacklist: return - if event_type not in CONF.wmf_keystone_eventtype_whitelist: + if event_type not in CONF.wmfhooks.eventtype_whitelist: return return diff --git a/modules/openstack/files/mitaka/keystone/wmfkeystonehooks/wmfkeystonehooks.py b/modules/openstack/files/mitaka/keystone/wmfkeystonehooks/wmfkeystonehooks.py index 70027ec..78c2796 100644 --- a/modules/openstack/files/mitaka/keystone/wmfkeystonehooks/wmfkeystonehooks.py +++ b/modules/openstack/files/mitaka/keystone/wmfkeystonehooks/wmfkeystonehooks.py @@ -13,8 +13,12 @@ # License for the specific language governing permissions and limitations # under the License. +from keystoneclient.auth.identity import generic +from keystoneclient import session as keystone_session from keystone.common import dependency from keystone import exception +from novaclient import client as nova_client +from novaclient import exceptions from oslo_log import log as logging from oslo_config import cfg @@ -36,6 +40,12 @@ cfg.StrOpt('admin_user', default='novaadmin', help='Admin user to add to all new projects'), + cfg.StrOpt('admin_pass', + default='', + help='Admin password, used to authenticate with other services'), + cfg.StrOpt('auth_url', + default='', + help='Keystone URL, used to authenticate with other services'), cfg.StrOpt('observer_user', default='novaobserver', help='Observer user to add to all new projects'), @@ -48,10 +58,10 @@ cfg.StrOpt('admin_role_name', default='projectadmin', help='Name of project-local admin role'), - cfg.MultiStrOpt('wmf_keystone_eventtype_whitelist', + cfg.MultiStrOpt('eventtype_whitelist', default=['identity.project.deleted', 'identity.project.created'], help='Event types to always handle.'), - cfg.MultiStrOpt('wmf_keystone_eventtype_blacklist', + cfg.MultiStrOpt('eventtype_blacklist', default=[], help='Event types to always ignore.' 'In the event of a conflict, ' @@ -60,7 +70,7 @@ CONF = cfg.CONF -CONF.register_opts(wmfkeystone_opts) +CONF.register_opts(wmfkeystone_opts, group='wmfhooks') @dependency.requires('assignment_api', 'resource_api', 'role_api') @@ -82,25 +92,75 @@ # Make a dict to relate role names to ids for role in rolelist: roledict[role['name']] = role['id'] - if CONF.observer_role_name not in roledict.keys(): - LOG.error("Failed to find id for role %s" % CONF.observer_role_name) + if CONF.wmfhooks.observer_role_name not in roledict.keys(): + LOG.error("Failed to find id for role %s" % CONF.wmfhooks.observer_role_name) raise exception.NotImplemented() - if CONF.admin_role_name not in roledict.keys(): - LOG.error("Failed to find id for role %s" % CONF.admin_role_name) + if CONF.wmfhooks.admin_role_name not in roledict.keys(): + LOG.error("Failed to find id for role %s" % CONF.wmfhooks.admin_role_name) raise exception.NotImplemented() - if CONF.user_role_name not in roledict.keys(): - LOG.error("Failed to find id for role %s" % CONF.user_role_name) + if CONF.wmfhooks.user_role_name not in roledict.keys(): + LOG.error("Failed to find id for role %s" % CONF.wmfhooks.user_role_name) raise exception.NotImplemented() - self.assignment_api.add_role_to_user_and_project(CONF.admin_user, + self.assignment_api.add_role_to_user_and_project(CONF.wmfhooks.admin_user, project_id, - roledict[CONF.admin_role_name]) - self.assignment_api.add_role_to_user_and_project(CONF.admin_user, + roledict[CONF.wmfhooks.admin_role_name]) + self.assignment_api.add_role_to_user_and_project(CONF.wmfhooks.admin_user, project_id, - roledict[CONF.user_role_name]) - self.assignment_api.add_role_to_user_and_project(CONF.observer_user, + roledict[CONF.wmfhooks.user_role_name]) + self.assignment_api.add_role_to_user_and_project(CONF.wmfhooks.observer_user, project_id, - roledict[CONF.observer_role_name]) + roledict[CONF.wmfhooks.observer_role_name]) + + # Use the nova api to set up security groups for the new project + auth = generic.Password( + auth_url=CONF.wmfhooks.auth_url, + username=CONF.wmfhooks.admin_user, + password=CONF.wmfhooks.admin_pass, + user_domain_name='Default', + project_domain_name='Default', + project_name=project_id) + session = keystone_session.Session(auth=auth) + client = nova_client.Client('2', session=session) + allgroups = client.security_groups.list() + defaultgroup = filter(lambda group: group.name == 'default', allgroups) + if defaultgroup: + groupid = defaultgroup[0].id + try: + client.security_group_rules.create(groupid, + ip_protocol='icmp', + from_port='-1', + to_port='-1', + cidr='0.0.0.0/0') + except (exceptions.ClientException): + LOG.warning("icmp security rule already exists.") + try: + client.security_group_rules.create(groupid, + ip_protocol='tcp', + from_port='22', + to_port='22', + cidr='10.0.0.0/8') + except (exceptions.ClientException): + LOG.warning("Port 22 security rule already exists.") + try: + client.security_group_rules.create(groupid, + ip_protocol='tcp', + from_port='5666', + to_port='5666', + cidr='10.0.0.0/8') + except (exceptions.ClientException): + LOG.warning("Port 5666 security rule already exists.") + try: + client.security_group_rules.create(groupid, + ip_protocol='tcp', + from_port='1', + to_port='65535', + cidr='', + group_id=groupid) + except (exceptions.ClientException): + LOG.warning("Project security rule already exists.") + else: + LOG.warning("Failed to find default security group in new project.") def notify(self, context, message, priority, retry=False): event_type = message.get('event_type') @@ -112,9 +172,9 @@ self._on_project_create(message['payload']['resource_info']) # Eventually this will be used to update project resource pages: - if event_type in CONF.wmf_keystone_eventtype_blacklist: + if event_type in CONF.wmfhooks.eventtype_blacklist: return - if event_type not in CONF.wmf_keystone_eventtype_whitelist: + if event_type not in CONF.wmfhooks.eventtype_whitelist: return return diff --git a/modules/openstack/templates/liberty/keystone/keystone.conf.erb b/modules/openstack/templates/liberty/keystone/keystone.conf.erb index 6ab3924..23c54a2 100644 --- a/modules/openstack/templates/liberty/keystone/keystone.conf.erb +++ b/modules/openstack/templates/liberty/keystone/keystone.conf.erb @@ -397,3 +397,9 @@ dbpass = <%= @keystoneconfig["oath_dbpass"] %> dbname = <%= @keystoneconfig["oath_dbname"] %> dbhost = <%= @keystoneconfig["oath_dbhost"] %> + +[wmfhooks] + +admin_pass = <%= @keystoneconfig["ldap_user_pass"] %> +auth_url = <%= @keystoneconfig["auth_protocol"] %>://<%= @fqdn %>:<%= @keystoneconfig["auth_port"] %>/v3 + diff --git a/modules/openstack/templates/mitaka/keystone/keystone.conf.erb b/modules/openstack/templates/mitaka/keystone/keystone.conf.erb index 6ab3924..688cfa5 100644 --- a/modules/openstack/templates/mitaka/keystone/keystone.conf.erb +++ b/modules/openstack/templates/mitaka/keystone/keystone.conf.erb @@ -397,3 +397,8 @@ dbpass = <%= @keystoneconfig["oath_dbpass"] %> dbname = <%= @keystoneconfig["oath_dbname"] %> dbhost = <%= @keystoneconfig["oath_dbhost"] %> + +[wmfhooks] + +admin_pass = <%= @keystoneconfig["ldap_user_pass"] %> +auth_url = <%= @keystoneconfig["auth_protocol"] %>://<%= @fqdn %>:<%= @keystoneconfig["auth_port"] %>/v3 -- To view, visit https://gerrit.wikimedia.org/r/332899 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I185651527faf0a44814a1acf3eea2ba5b64ad6bc Gerrit-PatchSet: 4 Gerrit-Project: operations/puppet Gerrit-Branch: production Gerrit-Owner: Andrew Bogott <abog...@wikimedia.org> Gerrit-Reviewer: Alex Monk <kren...@gmail.com> Gerrit-Reviewer: Andrew Bogott <abog...@wikimedia.org> Gerrit-Reviewer: Volans <rcocci...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits