smallstep / certificates

🛡️ A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH.
https://smallstep.com/certificates
Apache License 2.0
6.73k stars 440 forks source link

Allow token reuse within short timeframe to allow both CERT and SSH in one login #985

Closed Slamdunk closed 2 years ago

Slamdunk commented 2 years ago

Hello!

Issue details

Hi, currently to issue both a user certificate and a user ssh key, my users need to get 2 tokens from our provisioner, which means they are prompted twice to login into our IdP (Google).

I see that token reuse has been disallowed for security reasons, and of course that's correct.

But I guess we could safely allow to reuse the same token within a short timeframe after first use, like 5 minutes. Of course the token data themself cannot be used as are provisioner-specific, so token reuse expiration should be tracked separately.

Or we could track token usage to allow only separate context, like one for CERT and one for SSH but not two CERTS, but time expiration should be needed as well.

dopey commented 2 years ago

Hey @Slamdunk, thanks for opening the issue (and sorry it took so long to respond).

Rather than using the same OTT, our team's solution has been to use the x5c provisioner. You get a cert with an OTT as your first request and then you use that cert (using the x5c provisioner) to request an SSH cert. We use this same pattern in numerous places and specifically in our product, which implements a similar flow to the one you're looking to achieve.

You may want to add an SSH template on the x5c provisioner that could populate fields of the SSH certificate directly from attributes of the x509 certificate (e.g., taking the SANs of the cert to be principals of the SSH cert).

Let me know if you have any questions about that.

Slamdunk commented 2 years ago

You get a cert with an OTT as your first request and then you use that cert (using the x5c provisioner) to request an SSH cert.

Hi, I guess that in order to do that you are using the very same root certificate of step-ca for validating X5C tokens.

This puzzles me: as far as I can tell, such kind of provisioner defeats the purpose of every other provisioners. With every new certificate I get, I can request another new certificate with a refreshed time validity bypassing the renew feature. It is so, isn't it?

This would be a handy solution if X5C could be configured to not issue TLS certs but only SSH certs, but I don't see a counterpart of enableSSHCA in the doc.

Am I getting it right?

dopey commented 2 years ago

Good questions!

1) When you generate another credential using the x5c provisioner, the new credentials validity does not last beyond the validity of the original x5c Certificate. As an example, suppose my X509 certificate had a lifetime of 24h but at the time I used it with the x5c provisioner there was only 3 hours of validity left - the new credential would have a validity of 3 hours.

2) We don't have an option to disable X509, but you could set up an x509 template on the provisioner to just fail requests for x509 certificates.

Slamdunk commented 2 years ago
  1. When you generate another credential using the x5c provisioner, the new credentials validity does not last beyond the validity of the original x5c Certificate.

Nice, that's exactly what I expected :muscle: and correct me if I'm wrong, that's coded in:

  1. https://github.com/smallstep/certificates/blob/38fb92452f10169540c2519e96fc9125141707e7/authority/provisioner/x5c_test.go#L485
  2. https://github.com/smallstep/certificates/blob/38fb92452f10169540c2519e96fc9125141707e7/authority/provisioner/x5c.go#L240

The only thing I miss is mentioning it in the docs: https://github.com/smallstep/docs/pull/124

  1. We don't have an option to disable X509, but you could set up an x509 template on the provisioner to just fail requests for x509 certificates.

That's be nice, can you drop here some links on how to do it? Thank you :pray:

dopey commented 2 years ago

Thanks for opening the PR!

@maraino would you mind dropping an example of an x509 template that just throws an error, please?

maraino commented 2 years ago

one simple whitelist example:

{{ $whiteList := list "www.example.com" "example.com" "www.example.org" "example.org" }}
{
        "subject": {{ toJson .Subject }},
{{- range .SANs }}
        {{- if has .Value $whiteList | not }}
        {{ printf "SAN %s is not whitelisted" .Value | fail }}
        {{- end }}
{{- end }}
        "sans": {{ toJson .SANs }},
{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }}
        "keyUsage": ["keyEncipherment", "digitalSignature"],
{{- else }}
        "keyUsage": ["digitalSignature"],
{{- end }}
        "extKeyUsage": ["serverAuth", "clientAuth"]
}
dopey commented 2 years ago

So something like

{{ fail "X509 provisioning is disabled" }}
Slamdunk commented 2 years ago

Thank you very much