Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vault: cache the transport certificate on client #476

Closed
wants to merge 1 commit into from
Closed

vault: cache the transport certificate on client #476

wants to merge 1 commit into from

Conversation

HonzaCholasta
Copy link
Contributor

@HonzaCholasta HonzaCholasta commented Feb 17, 2017

Copy link
Member

@tiran tiran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work!

I left a couple of comments and I'm going to update the issue with to action items.

raise
with tempfile.NamedTemporaryFile(dir=TRANSPORT_CERT_CACHE_PATH,
delete=False) as f:
f.write(data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's safer to close or at least flush the file.

Feel free to ignore the problem for now and replace the function later with David's helper function from PR #467.

set_cached_transport_cert(api.env.domain, transport_cert)
else:
transport_cert_der = (
transport_cert.public_bytes(serialization.Encoding.DER))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this functionality to a plugin or some other place. I like to fetch and cache the KRA transport cert every time Custodia is started. The API should have an optional argument to force a refresh.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not what was requested in the ticket...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, what's the point? Is there a design or PoC for Custodia that I can take a look at?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was obvious to me that the certificate is retrieved and cached in the main process at start-up. It's faster and avoids so many issues with concurrent reads and writes in concurrent processes. In fact it was so obvious to me that I did not consider any other approach when I wrote the ticket.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in-memory caching in the last update.

Copy link
Member

@tiran tiran Mar 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An in-memory cache does not work for Custodia because it is a forking webserver. It has to be an API call that ignores any caches (file) and downloads the KRA transport cert from remote server.

if e.errno != errno.ENOENT:
raise
except Exception as e:
logger.warning("Failed to load %s: %s", filename, e)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use exc_info=True everywhere in order to get a full traceback. It makes debugging much more pleasant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

except (errors.InternalError,
errors.ExecutionError,
errors.GenericError):
del_cached_transport_cert(api.env.domain)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This removes the cached key in any case of error. That's OK for a PoC. For the final version we should be more clever and only delete the certificate when it is not recognized by the KRA. I'll figure out the exact error message.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KRA subsystem doesn't report invalid KRA transport cert correctly, https://fedorahosted.org/pki/ticket/2597

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache is deleted only in case of an unexpected error, which is why there is a list of them, not in case of any error.

The KRA bug should definitely be fixed, but we should still cache the cert properly even for older servers.

Copy link
Member

@tiran tiran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work! exc_info() can lead to memory-leak like reference cycles. See inline comment

except (errors.InternalError,
errors.ExecutionError,
errors.GenericError):
raise _TransportCertInvalid(sys.exc_info())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sys.exc_info() is problematic. It returns a stack frame object, which usually creates a reference cycle that keeps all local objects alive. If any object has __del__ method, then Python 2 is unable to break the reference cycle. It's rather bad for long running processes because it is a kind of memory leak.

Here are two reasonable well written blog postings that I just found

Proposal:

class _TransportCertInvalid(Exception):
    def __init__(self, exception):
        self.inner = exception

and

        except (errors.InternalError,
                     errors.ExecutionError,
                     errors.GenericError) as e:
            root_logger.debug("some message", exc_info=True)
            raise _TransportCertInvalid(e)

later:

six.reraise(type(e.inner), e.inner, None)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no local variable which would hold the reference to the sys.exc_info() result or the _TransportCertInvalid exception. Is raising the exception enough to create a reference to it?

"""
domain = self.api.env.domain
dirname = TRANSPORT_CERT_CACHE_PATH
basename = DNSName(domain).ToASCII() + '.pem'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about DNSName(domain).ToASCII() + '-kra-transport.pem' to make the purpose of the cert clear?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a bit redundant to me, since the full path is ~/.cache/ipa/kra-transport-certs/$DOMAIN.pem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scratch my proposal. I didn't notice that you are using an extra directory just for KRA transport certs. Sorry.

except _TransportCertInvalid:
_transport_cert_cache.pop(domain, None)
try:
os.remove(filename)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit pick: os.unlink. Unix developers don't remove files. We unlink names from inodes. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right 😄

@tiran
Copy link
Member

tiran commented Mar 2, 2017

I didn't see your comment regarding the in-memory cache because github hid the section after your most recent push.

The in-memory cache doesn't work for Custodia because Custodia is a forking webserver. Requests are handled in one-shot client processes. I must be able to forcefully download the certificate in the main process, before it starts listening on incoming requests.

@HonzaCholasta
Copy link
Contributor Author

Calling vaultconfig_show now refreshes the cache, you can call it to download and cache the certificate in the main process.

@MartinBasti
Copy link
Contributor

needs rebase

Cache the KRA transport certificate on disk (in ~/.cache/ipa) as well as
in memory.

https://fedorahosted.org/freeipa/ticket/6652
@MartinBasti
Copy link
Contributor

Works for me

@MartinBasti MartinBasti added ack Pull Request approved, can be merged pushed Pull Request has already been pushed labels Mar 13, 2017
@MartinBasti
Copy link
Contributor

master:

  • 98bb539 vault: cache the transport certificate on client

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ack Pull Request approved, can be merged pushed Pull Request has already been pushed
Projects
None yet
3 participants