- 
                Notifications
    
You must be signed in to change notification settings  - Fork 57
 
Description
We have a regulatory requirement to enable multi-factor auth in our OpenStack deployment, so we want to require users to supply client certificates in addition to their regular password-based credentials. In the upstream clients based on python-keystoneclient, this usecase is supported via the OS_CERT and OS_KEY environment variables (or respective clouds.yaml entries).
The gophercloud/utils API somewhat supports OS_CERT/OS_KEY and their sibling OS_CACERT , but only in clientconfig.NewServiceClient, not in the much more important clientconfig.AuthOptions and clientconfig.AuthenticatedClient calls.
For us, that means that the only choice in the short term is to patch client certs into the ProviderClient.HTTPClient manually, like in sapcc/limesctl#122. This feels like something that Gophercloud should cover.
The main issue is that both clientconfig.AuthOptions and clientconfig.AuthenticatedClient are constrained by the capabilities of the gophercloud.AuthOptions type, which does not have any API surface for TLS certificates. In clientconfig.AuthOptions, the constraint is visible from the outside since gophercloud.AuthOptions is the return value for this function. In clientconfig.AuthenticatedClient, the constraint is less obvious: Its implementation defers most of the work to openstack.AuthenticatedClient which takes a single gophercloud.AuthOptions argument.
Proposal
Right now, as far as I can see, the best that we can do is to change Gophercloud to:
- add new fields to 
gophercloud.AuthOptionsthat cover TLS client certs and CA certs- option 1: in the same way that the env vars as structured (
ClientCertFile, ClientKeyFile, CACertFile string) -> advantage: clear semantics - option 2: allow a custom 
http.Clientto be injected (HTTPClient *http.Client) -> advantage: same pattern as inclientconfig.ClientOpts, so we would have the chance to also fix this field to work properly all the time 
 - option 1: in the same way that the env vars as structured (
 - have 
openstack.AuthenticatedClientrespect those fields (i.e. set up theProviderClient.HTTPClientthusly before moving on intoopenstack.Authenticate) 
Once Gophercloud has cut a new release after these changes, gophercloud/utils can be changed to:
- have 
clientconfig.AuthOptionsfill the new fields in its return value appropriately from env vars and clouds.yaml - have 
clientconfig.AuthOptionscarry forward theClientOpts.HTTPClientfield into its return value (if option 2 was chosen above) 
The ugly part here is that there are several intended paths to obtain a gophercloud.ProviderClient, but we can only fix some of them (specifically, all that go through openstack.AuthenticatedClient). To support the new AuthOptions fields in all possible paths, openstack.NewClient would have to be amended, but its API is too narrow.
When Gophercloud breaks API compatibility next time, I propose to:
- change 
openstack.NewClient()from taking a singleendpoint stringargument to taking a struct of at leastendpoint stringplus the TLS-related options - change 
gophercloud.AuthOptionsto have that struct type as a field in it (thus grouping all the options together that are needed for theNewClientstep) 
I'm willing to contribute dev time on our team to implement these changes, but I would like to align with you first before starting on the implementation.
cc @talal @databus23