ansible-collections / community.crypto

The community.crypto collection for Ansible.
https://galaxy.ansible.com/ui/repo/published/community/crypto/
Other
100 stars 89 forks source link

Entrust API request cert list for account #315

Open aworldofcode opened 3 years ago

aworldofcode commented 3 years ago
SUMMARY

Ability to request of all entrust certs belonging to an account

ISSUE TYPE
COMPONENT NAME

Entrust api plugin

ADDITIONAL INFORMATION

It solves the ability to update information pertinent to certs that have been generated for the account requesting the cert list

felixfontein commented 3 years ago

CC @ctrufan

ctrufan commented 3 years ago

Thanks for the CC @felixfontein !

While the Entrust API itself supports this, I'm not sure how cleanly it would fit into any of the existing ansible modules or workflows. If we download all the certificates to a file, it would be an overload of information for the user (and possibly not include the information a user is looking for, such as custom fields, which aren't directly part of a certificate). If we print it out during the ansible run, it's something the user would need to manually comb through.

Being able to run narrower queries (e.g. "Get me certificates with X domain" could be useful for the workflow where you want a certificate to be 'ansible managed' but it isn't yet, but we then run into the issue that for many customers there would be huge overlap (many certificates that might be applicable) - that's why the current flow supports "specify a tracking ID, and Ansible can start managing the certificate" but doesn't support other query parameters.

Depending on an end user's use case, it might be more useful to have, for example, a powershell script to query the Entrust API and return all certificates, that you could then parse through for whatever information is desired.

A bit more information about the desired use case here might help me provide better feedback.

felixfontein commented 3 years ago

how cleanly it would fit into any of the existing ansible modules

Just a note from me: I wouldn't add it to an existing ansible module, but create a new one (an _info module). But what exactly that module should do and what interface it should have (or whether there should be multiple modules, or whether there should be one at all ;) ) is still something that needs to be determined.

aworldofcode commented 3 years ago

In my case I would be looking for the ability to get all the certificates. It would end up being a pretty big JSON payload in some cases but that is ok as we can iterate it in ansible for further dissection. Of course we should have options to subfilter if needed

aworldofcode commented 3 years ago

Any updates on this ? Has there been a decision to move forward ? I think that as @ctrufan mentioned, it seems that the ability to get a list of certs, all or based on options is already backed in the API. Should not be that hard to give the module access to it.

MarkusTeufelberger commented 3 years ago

So you're proposing some kind of entrust_account_info plugin, right?

I'm not 100% sure if that should go into this collection or something more entrust specific (testing this sounds like it won't easily be possible for example), but I guess that can also be sorted out later. Do you offer to write this module yourself, @aworldofcode or are you expecting someone from entrust to write it for you? Just for the record, I don't work there and am also not one of their customers.

aworldofcode commented 3 years ago

@MarkusTeufelberger I think that being able to get a list of certificates with options is as valuable as creating certificates. There are a couple of modules that are Entrust specific using the ecs plugin, I dont see why listing/getting info would be a separate module than creating entrust certs and having the need to create a separate entrust entrust_account_info module, not opposed to separate module either. Listing certs is different for different providers so an agnostic cert_account_info would not be in play. I don't think I have the toolset to write the module but it would be a spinoff of the ecs_certificate module as the authentication piece is already in place and both piggy back on ecs plugin. On the other hand I can test that it works as we do have an account with entrust

felixfontein commented 3 years ago

@aworldofcode the ansible way is to have _info modules for data querying, and other modules for data modification. So if this is added to this collection, it will be a separate module.

aworldofcode commented 3 years ago

@felixfontein Love the fact I am now learning the ansible_way. In this case I am 100% on board with an info module. Buffering the info registers makes ansible so much more powerful as a one stop solution.

aworldofcode commented 2 years ago

Hello guys, any update on this ?

felixfontein commented 2 years ago

I'm not aware of anyone working on this.

ctrufan commented 2 years ago

I don't have the cycles or plan to work on this.

aworldofcode commented 2 years ago

I can probably try to put something together but I am not fully versed in creating ansible modules or py. that's why the current flow supports "specify a tracking ID, and Ansible can start managing the certificate" but doesn't @ctrufan You mentioned 'that's why the current flow supports "specify a tracking ID, and Ansible can start managing the certificate" but doesn't support other query parameters.' Do you mean that there is already a spec in the current module that checks a certificate with a tracking ID ? I could look at that code and work from it

ctrufan commented 2 years ago

The current ecs_certificate module supports specifying a tracking ID when you're specifying certification location/etc, and it will download that individual certificate to start managing it (so the idea is that for a fresh setup of a server that doesn't have a cert, you specify the details and end up with a cert, but if you already have one, you specify the tracking ID, and then running the playbook will renew that certificate when it comes close to expiry). But for the use case we're talking about here, we would want to use a different API endpoint.

So while the ecs_certificate module calls something like self.cert_details = self.ecs_client.GetCertificate(trackingId=self.tracking_id) you would instead be building different body contents and doing a (note that "Certificate" is plural) self.ecs_client.GetCertificates(Body = body)

Where the parameters in Body could be the (optional) filter parameters that are in the "GetCertificates" operation in the ECS API specification. (status, dn, serialNumber, etc). One of the tricky things is that in order to support any of the filters, you would need to define a format and convert the filter parameters, because many of them support things like lists - for example, the status filter can be "status=ACTIVE" or it can be "status=in:ACTIVE,READY,PENDING" to return all certificates with any one of those statuses.

For a bare bones operation, you could literally just call self.ecs_client.GetCertificates with no additional parameters to get one page worth of certificates.

This would not fit (thematically, or make sense given what the module does) in the existing modules, so it would be an ecs_certificate_info module or similar, which would also entail documenting parameters, and so on.

I'd be happy to help with testing and reviews, but it's unfortunately not just a matter of copying some of the code from ecs_certificate. Fortunately the actual API call is already supported by the ecs_client module utility (which builds all available API calls from the specification), so there's a "GetCertificates" that can be called - the hard part is building all the ansible stuff around it to make the request.

You can see the ECS client put together in the following line of code: https://github.com/ansible-collections/community.crypto/blob/5de50b9f914c106c48eff7c3ed48fc80b3f7fd0e/plugins/modules/ecs_certificate.py#L604 (604 through 623)

aworldofcode commented 2 years ago

@ctrufan Thank you for the insight. I am making strives and I am able to GET certificates but I am having issue understanding how to add a $ref like limit and offset, we don't understand how to add to the request , do we add as a parameters or a $ref ? Would I be able to reference the CRUD for things like limit and offset by adding something via Body like self.ecs_client.GetCertificates(Body = limit:100 )

I see in api.py ` if query_parameters:

modify the URL to add path parameters

        url = url + "?" + urlencode(query_parameters)

` but I am not sure how to reference query_parameters for options parameters that dont fall under paths like limit and offset or as $ref

ctrufan commented 2 years ago

When something is referred to as "$ref" in an OpenAPI specification, it's a specific OpenAPI term (short for "reference"). So something like "ref: '#parameters/limit" is really saying "this operation also includes the contents of the "parameters/limit" object. You can almost think of it like inheritance in object oriented programming - so the operation includes all the parameters listed directly, plus anything that's listed as a reference (I guess it would be more accurate to call it aggregation than inheritance).

So if you look towards the very bottom of the specification, there's values "sort", "offset", and "limit" defined - those are also part of the available request parameters.

So for Body, you could include a limit that is an integer (minimum 1, maximum 1000). I can't recall offhand (python is rusty) if how you defined it there is correct - but you could include the key/value mapping of limit=100 similar to how you see Body defined elsewhere in some of the existing flows.

aworldofcode commented 2 years ago

tried to do key mapping in all kind of ways but I have exhausted figuring out how to pass back information to api.py query_parameters. What seems to work instead is modifying the apy.py.

api.py

 def restmethod(self, *args, **kwargs):
 ......

 elif expected_location == "query" and key_name and key_value:
   query_parameters.update({key_name: key_value})

        if(kwargs.get('limit')):
            query_parameters.update({'limit': kwargs.get('limit')})

        if(kwargs.get('offset')):
            query_parameters.update({'offset': kwargs.get('offset')})

ecs_info.py

       def get_all_certificates(self, module):
       ...  

        certificates = self.ecs_client.GetCertificates(limit=self.limit)
        self.all_certificates = certificates.get('certificates',{})
        self.summary = certificates.get('summary',{})

        return
ctrufan commented 2 years ago

Sorry about that! It looks like you've identified an area the api.py is incomplete - basically, it autogenerates the allowable parameters based on reading the specification (and figures out where they need to go), but it looks like it doesn't handle the "$ref" parameters.

So as you identified in order to support limit/offset/sort, you'll need to update api.yml.

aworldofcode commented 2 years ago

I updated the API and now everything seems to work, Do we want to upstream the changes in the api ? I am not sure what the process is to create PR's in this project