<div dir="ltr">Hoping I can leverage the wisdom of the ML for a follow-up point on this topic...<div><br></div><div>I've coded this up now following Aditya's suggestion, but the issue now is about the Neutron user (or more generally, whatever is configured in neutron.conf's [keystone_authtoken] section) being authorized to do a keystone.projects.list().</div><div><br></div><div>IIUC that is considered to be an admin operation, and the Neutron user is not normally authorized to do it. However, it seems reasonable to me that the operator of a particular deployment can choose to allow that if they want to, and I see two approaches to doing that:</div><div><br></div><div>1. Add the "admin" role to the "neutron" user. I have code for this that seems to work, and append it below for interest and review [1].</div><div><br></div><div>2. Modify Keystone's RBAC specifically to allow "neutron" to do "get_projects". I don't yet know how to do this, though.</div><div><br></div><div>My questions are: Am I in the right ballpark here? Are there any other approaches to allowing this access, ideally as specifically as possible? And in case (2) is the preferred approach, can you point me to how to modify that RBAC?</div><div><br></div><div>Many thanks,</div><div> Neil</div><div><br></div><div><br></div><div>[1] Apparently working code for adding the "admin" role to the "neutron" user:</div><div><br></div><div><div># Admin client setup:</div><div>>>> auth_url="<a href="http://controller:35357/v3">http://controller:35357/v3</a>"</div><div>>>> name = "admin"</div><div>>>> password = "abcdef"</div><div>>>> from keystoneauth1 import identity</div><div>>>> auth = identity.Password(auth_url=auth_url,</div><div>... username=name,</div><div>... password=password,</div><div>... project_name=name,</div><div>... project_domain_id="default",</div><div>... user_domain_id="default")</div><div>>>> from keystoneauth1 import session</div><div>>>> session = session.Session(auth=auth)</div><div>>>> from keystoneclient.v3.client import Client as KeystoneClient</div><div>>>> keystone_client = KeystoneClient(session=session)</div><div><br></div><div># Identify which role is the "admin" one:</div><div>>>> roles=keystone_client.roles.list()</div><div>>>> roles[0]</div><div><Role domain_id=None, id=9fe2ff9ee4384b1894a90878d3e92bab, links={u'self': u'<a href="http://controller:35357/v3/roles/9fe2ff9ee4384b1894a90878d3e92bab'">http://controller:35357/v3/roles/9fe2ff9ee4384b1894a90878d3e92bab'</a>}, name=_member_></div><div>>>> roles[1]</div><div><Role domain_id=None, id=d0a84ecdad284fecb9b215126b5fbe05, links={u'self': u'<a href="http://controller:35357/v3/roles/d0a84ecdad284fecb9b215126b5fbe05'">http://controller:35357/v3/roles/d0a84ecdad284fecb9b215126b5fbe05'</a>}, name=admin></div><div><br></div><div># Identify which project is the "service" one:</div><div>>>> projects=keystone_client.projects.list()</div><div>>>> projects[0]</div><div><Project description=Bootstrap project for initializing the cloud., domain_id=default, enabled=True, id=6274ae6b92634389a4a5eda4093035c3, is_domain=False, links={u'self': u'<a href="http://controller:35357/v3/projects/6274ae6b92634389a4a5eda4093035c3'">http://controller:35357/v3/projects/6274ae6b92634389a4a5eda4093035c3'</a>}, name=admin, parent_id=default, tags=[]></div><div>>>> projects[1]</div><div><Project description=Service Project, domain_id=default, enabled=True, id=7837dbe6b5294ce89342dec823fea106, is_domain=False, links={u'self': u'<a href="http://controller:35357/v3/projects/7837dbe6b5294ce89342dec823fea106'">http://controller:35357/v3/projects/7837dbe6b5294ce89342dec823fea106'</a>}, name=service, parent_id=default, tags=[]></div><div><br></div><div># Identify which user is the "neutron" one:</div><div>>>> users=keystone_client.users.list()</div><div>>>> users[0]</div><div><User domain_id=default, enabled=True, id=113dc98e751d4720b4573044df6eb870, links={u'self': u'<a href="http://controller:35357/v3/users/113dc98e751d4720b4573044df6eb870'">http://controller:35357/v3/users/113dc98e751d4720b4573044df6eb870'</a>}, name=neutron, options={}, password_expires_at=None></div><div><br></div><div># Grant "admin" role to "neutron":</div><div>>>> keystone_client.roles.grant(roles[1], user=users[0], project=projects[1])</div><div><br></div><div># And to revoke that again:</div><div>>>> keystone_client.roles.revoke(roles[1], user=users[0], project=projects[1])</div></div><div><br></div><div><br></div><div><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Jul 17, 2018 at 7:17 PM Neil Jerram <<a href="mailto:neil@tigera.io">neil@tigera.io</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Thanks Aditya, that looks like just what I need.<div><br></div><div>Best wishes,</div><div> Neil</div></div><div dir="ltr"><div><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Jul 17, 2018 at 5:48 PM Aditya Vaja <<a href="mailto:wolverine.av@gmail.com" target="_blank">wolverine.av@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><img class="m_9204426204806153029m_2015242018185101825cloudmagic-smart-beacon" src="https://tr.cloudmagic.com/h/v6/emailtag/tag/2.0/1531846037/b6586376ba15a888edaa3fef1d6cd876/1/4abed602a779b81dcfeb5722ef069770/08468a2bbee7e844805e6216c2949e71/5f2f354b1d73f9ab1e2e1222558f1320/newton.gif" style="border:0;width:10px;height:10px" width="10" height="10" align="right"><div dir="auto"><span>hey neil,</span><div><span><br></span></div><div><span>neutron.conf has a section called '</span>[keystone_authtoken]’ which has credentials to query keystone as neutron. you can read the config as you’d typically do from the mechanism driver for any other property using oslo.config.</div><div><br></div><div>you could then use python-keystoneclient with those creds to query the mapping. a sample is given in the keystoneclient repo [1].</div><div><br></div><div><div id="m_9204426204806153029m_2015242018185101825cm_footer" class="m_9204426204806153029m_2015242018185101825cm_footer"><div id="m_9204426204806153029m_2015242018185101825cm_signature">via telegram</div><div id="m_9204426204806153029m_2015242018185101825cm_signature"><br></div><div id="m_9204426204806153029m_2015242018185101825cm_signature">[1] <a href="https://github.com/openstack/python-keystoneclient/blob/650716d0dd30a73ccabe3f0ec20eb722ca0d70d4/keystoneclient/v3/client.py#L102-L116" target="_blank">https://github.com/openstack/python-keystoneclient/blob/650716d0dd30a73ccabe3f0ec20eb722ca0d70d4/keystoneclient/v3/client.py#L102-L116</a></div></div><div id="m_9204426204806153029m_2015242018185101825cm_replymail_content_wrap"><div class="m_9204426204806153029m_2015242018185101825cm_replymail_content_1531845706_wrapper"></div></div></div></div><div dir="auto"><div><div id="m_9204426204806153029m_2015242018185101825cm_replymail_content_wrap"><div class="m_9204426204806153029m_2015242018185101825cm_replymail_content_1531845706_wrapper">On Tue, Jul 17, 2018 at 9:58 PM, Neil Jerram <<a href="mailto:neil@tigera.io" target="_blank">neil@tigera.io</a>> wrote:<br></div></div></div></div><div dir="auto"><div><div id="m_9204426204806153029m_2015242018185101825cm_replymail_content_wrap"><div class="m_9204426204806153029m_2015242018185101825cm_replymail_content_1531845706_wrapper"><div id="m_9204426204806153029m_2015242018185101825cm_replymail_content_1531845706" style="overflow:visible"><blockquote style="margin:0;border-left:#d6d6d6 1px solid;padding-left:10px"><div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Tue, Jul 17, 2018 at 3:55 PM Jay Pipes <<a href="mailto:jaypipes@gmail.com" target="_blank">jaypipes@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 07/17/2018 03:36 AM, Neil Jerram wrote:<br>
> Can someone help me with how to look up a project name (aka tenant name) <br>
> for a known project/tenant ID, from code (specifically a mechanism <br>
> driver) running in the Neutron server?<br>
> <br>
> I believe that means I need to make a GET REST call as here: <br>
> <a href="https://developer.openstack.org/api-ref/identity/v3/index.html#projects" rel="noreferrer" target="_blank">https://developer.openstack.org/api-ref/identity/v3/index.html#projects</a>. But <br>
> I don't yet understand how a piece of Neutron server code can ensure <br>
> that it has the right credentials to do that. If someone happens to <br>
> have actual code for doing this, I'm sure that would be very helpful.<br>
> <br>
> (I'm aware that whenever the Neutron server processes an API request, <br>
> the project name for the project that generated that request is added <br>
> into the request context. That is great when my code is running in an <br>
> API request context. But there are other times when the code isn't in a <br>
> request context and still needs to map from a project ID to project <br>
> name; hence the question here.)<br>
<br>
Hi Neil,<br>
<br>
You basically answered your own question above :) The neutron request <br>
context gets built from oslo.context's Context.from_environ() [1] which <br>
has this note in the implementation [2]:<br>
<br>
# Load a new context object from the environment variables set by<br>
# auth_token middleware. See:<br>
# <br>
<a href="https://docs.openstack.org/keystonemiddleware/latest/api/keystonemiddleware.auth_token.html#what-auth-token-adds-to-the-request-for-use-by-the-openstack-service" rel="noreferrer" target="_blank">https://docs.openstack.org/keystonemiddleware/latest/api/keystonemiddleware.auth_token.html#what-auth-token-adds-to-the-request-for-use-by-the-openstack-service</a><br>
<br>
So, basically, simply look at the HTTP headers for HTTP_X_PROJECT_NAME. <br>
If you don't have access to a HTTP headers, then you'll need to pass <br>
some context object/struct to the code you're referring to. Might as <br>
well pass the neutron RequestContext (derived from oslo_context.Context) <br>
to the code you're referring to and you get all this for free.<br>
<br>
Best,<br>
-jay<br>
<br>
[1] <br>
<a href="https://github.com/openstack/oslo.context/blob/4abd5377e4d847102a4e87a528d689e31cc1713c/oslo_context/context.py#L424" rel="noreferrer" target="_blank">https://github.com/openstack/oslo.context/blob/4abd5377e4d847102a4e87a528d689e31cc1713c/oslo_context/context.py#L424</a><br>
<br>
[2] <br>
<a href="https://github.com/openstack/oslo.context/blob/4abd5377e4d847102a4e87a528d689e31cc1713c/oslo_context/context.py#L433-L435" rel="noreferrer" target="_blank">https://github.com/openstack/oslo.context/blob/4abd5377e4d847102a4e87a528d689e31cc1713c/oslo_context/context.py#L433-L435</a></blockquote><div><br></div><div>Many thanks for this reply, Jay.</div><div><br></div><div>If I'm understanding fully, I believe it all works beautifully so long as the Neutron server is processing a specific API request, e.g. a port CRUD operation. Then, as you say, the RequestContext includes the name of the project/tenant that originated that request.</div><div><br></div><div>I have an additional requirement, though, to do a occasional audit of standing resources in the Neutron DB, and to check that my mechanism driver's programming for them is correct. To do that, I have an independent eventlet thread that runs in admin context and occasionally queries Neutron resources, e.g. all the ports. For each port, the Neutron DB data includes the project_id, but not project_name, and I'd like at that point to be able to map from the project_id for each port to project_name.</div><div><br></div><div>Do you have any thoughts on how I could do that? (E.g. perhaps there is some way of generating and looping round a request with the project_id, such that the middleware populates the project_name... but that sounds a bit baroque; I would hope that there would be a way of doing a simpler Keystone DB lookup.)</div><div><br></div><div>Regards,</div><div> Neil</div><div><br></div></div></div>
<br></blockquote></div></div></div></div></div><div dir="auto"><div><div id="m_9204426204806153029m_2015242018185101825cm_replymail_content_wrap"><div class="m_9204426204806153029m_2015242018185101825cm_replymail_content_1531845706_wrapper"><div id="m_9204426204806153029m_2015242018185101825cm_replymail_content_1531845706" style="overflow:visible"><blockquote style="margin:0;border-left:#d6d6d6 1px solid;padding-left:10px">__________________________________________________________________________
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: <a href="http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe" target="_blank">OpenStack-dev-request@lists.openstack.org?subject:unsubscribe</a>
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a>
</blockquote></div></div></div></div></div>__________________________________________________________________________<br>
OpenStack Development Mailing List (not for usage questions)<br>
Unsubscribe: <a href="http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe" rel="noreferrer" target="_blank">OpenStack-dev-request@lists.openstack.org?subject:unsubscribe</a><br>
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" rel="noreferrer" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br>
</blockquote></div></div></div></blockquote></div></div></div>