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

step certificate sign add name constraints #718

Open
LecrisUT opened this issue Aug 9, 2022 · 10 comments
Open

step certificate sign add name constraints #718

LecrisUT opened this issue Aug 9, 2022 · 10 comments
Assignees

Comments

@LecrisUT
Copy link
Contributor

LecrisUT commented Aug 9, 2022

Hello!

  • Vote on this issue by adding a 👍 reaction
  • If you want to implement this feature, comment to let us know (we'll work with you on design, scheduling, etc.)

Issue details

Although this can be done via template, it would be more useful to have it in the cli and to have it available to the csr as well (sign the csr as is, but add some constraints).

Why is this needed?

Particularly useful for signing an intermediate certificate offline and limiting it to a subset of domains like in my previous example #717

@LecrisUT LecrisUT added enhancement needs triage Waiting for discussion / prioritization by team labels Aug 9, 2022
@maraino
Copy link
Collaborator

maraino commented Aug 10, 2022

Hi @LecrisUT, one of the reasons that we created templates was to avoid adding flags for all things that can go in a certificate.

To do this, you will create a template:

{
	"subject": {{ toJson .Subject }},
	"keyUsage": ["certSign", "crlSign"],
	"basicConstraints": {
		"isCA": true,
		"maxPathLen": 0
	},
	"nameConstraints": {
		"critical": true,
		"permittedDNSDomains": [".example.com"]
	}
}

And run this:

$ step certificate create --csr "My Intermediate CA" my.csr my.key
$ step certificate sign --template name-constraints.tpl my.csr root_ca.crt root_ca_key

Although it would be possible to create a CSR with the same extension, you will need to encode the extension itself manually and sign with a template that takes the RAW certificate request like this:

{{ toJson .Insecure.CR }}

This process can be tedious, and I see the case for #717. But at the same time, I see more benefit of adding --template to step ca init and perhaps another flag to pass the intermediate key. In any case, all this can be achieved with a little bit of scripting.

If we add --template to step ca init, would that address your concerns? Would you like to be able to pass the intermediate key too?

@LecrisUT
Copy link
Contributor Author

Regarding this part of the issue, using the template we do not preserve the same fields that the csr was requesting right? That's why I was considering better as a flag in order to use it together with --csr just like --not-after works. Alternatively, we could add a functionality that --template and --csr flags together copy all of the original fields first, then override them with template values.

About templates, it can be tedious to design one for each use-case, so how about something more similar to how openstack does it. I.e., they provide a giant template with all features they support, then we enable/define each feature by passing --environment that are just json/yaml of the necessary fields you want to define/override. For example here instead of --template original --environment with:

nameConstraints:
  critical: true
  permittedDNSDomains:
    - .example.com

Another (not exclusive) way to allow these extension is to use jinja modules and add template jinja files that simply override each module section. The only potential confusion there would be, when does the jinja file override the base, and when does it extend. Although, this feature might not even be available in go's engine.

@maraino
Copy link
Collaborator

maraino commented Aug 11, 2022

Regarding this part of the issue, using the template we do not preserve the same fields that the csr was requesting right?

It actually depends on the template, you can achieve that if you want, my template doesn't do that, but you have access to the CSR using .Insecure.CR.

Our templates have already the ability to use variables and replace values on it from a file from a key=value flag. I thought it was available in step certificate create and step certificate sign, but it doesn't look like it. I will create an issue to add it.

I can also provide you with a template with all or most of the features if you want. You can always see the JSON tags and types here

@maraino
Copy link
Collaborator

maraino commented Aug 11, 2022

FYI, just added this #719

@LecrisUT
Copy link
Contributor Author

Ok, I think we're almost there. .Insecure.CR is the full certificate or a flag? If it's the former how do we override dictionary items afterwards? If it's the latter this would get the csr + constraints right:

{
  {{ toJson .Insecure.CR }},
  "nameConstraints": {
    "permittedDNSDomains": [".example.com"]
  }
}

I can also provide you with a template with all or most of the features if you want.

Isn't that the case for the built-in template? Doesn't the template engine support if expansions?

@maraino
Copy link
Collaborator

maraino commented Aug 15, 2022

.Insecure.CR is the full certificate signing request as we see it CertificateRequest, very similar to x509.CertificateRequest, so you cannot use it exactly like that as it will not create a valid JSON.

Manipulating the JSON directly might be difficult, so it will be better to access the properties you're interested in, e.g. the subject is {{ .Inscure.CR.Subject }}, using the Go fields, not the JSON names. And extend that with name and basic constraints extensions, here for example I'm doing that including also extensions present if the CSR:

{
  "subject": {{ toJson .Insecure.CR.Subject }},
  "extensions": {{ toJson .Insecure.CR.Extensions }},
  "nameConstraints": {
    "permittedDNSDomains": [".example.com"]
  },
  "basicConstraints": {
    "isCA": true,
    "maxPathLen": 0
  }
}

In most cases, you will not need the extensions in CSR extensions as you can define them in the certificate template.

And then:

step certificate sign --template my.tpl my.csr root_ca.crt root_ca.key

@LecrisUT
Copy link
Contributor Author

Hmm, isn't this a compelling reason to change the behavior of hot step certificate sign behaves when combining --template and --csr? I.e.:

  • Scenario 1: We want to override all/most csr fields: we use only --template and access what we want to keep via .Insecure.CR (Currently implemented)
  • Scenario 2: We want only the original csr fields: we use only --csr (Currently implemented)
  • Scenario 3: We want to override some csr fields: combine --csr and --template flags (Not implemented)

This should cover any ambiguity in the template when fields are not specified: if we want to include them, add --csr, if we want to make sure nothing else is included, do not add --csr. I only took a quick look at the relevant code, and I can't find a quick way to implement this, so it might take some re-coding to achieve this.

@maraino
Copy link
Collaborator

maraino commented Aug 17, 2022

You can do Scenario 3 too. You can for example loop through all the extensions in the template and include only the ones that you want to use.

And just to clarify, with --csr you're referring to --profile csr in step certificate sign, right?

@LecrisUT
Copy link
Contributor Author

You can do Scenario 3 too. You can for example loop through all the extensions in the template and include only the ones that you want to use.

Scenario 3 is the opposite. For example, you want to include all the subject, basicConstraints, extensions of the original csr, but you want to add on top of that one more extension. Or in the case of this issue, you want all of the csr mentioned fields, but add namedConstraints.

If we wanted to override the extensions, that would be Scenario 1.

But about #719, that should solve most Scenario 3 usecases, but setting extensions would overwrite the whole list, right? We would still need a functionality of combining --profile csr with either --template or --set so that it merges instead of overwrites.

And just to clarify, with --csr you're referring to --profile csr in step certificate sign, right?

yes

@maraino
Copy link
Collaborator

maraino commented Aug 17, 2022

Hi @LecrisUT, I've added a PR with some of the things we've been talking about, the --set and --set-file flags in step certificate sign and step certificate create.

For example, if you have two labs you can use those flags to customize the automation of different certificates without modifying the template:

$ cat intermediate.tpl
{
	"subject": {
		"country": {{ toJson .Insecure.User.country }},
		"organization": {{ toJson .Insecure.User.organization }},
		"organizationalUnit": {{ toJson .Insecure.User.organizationUnit }},
		"commonName": {{toJson .Subject.CommonName }}
	},
	"keyUsage": ["certSign", "crlSign"],
	"basicConstraints": {
		"isCA": true,
		"maxPathLen": 0
	}
}
$ cat organization.json
{
	"country": "US",
	"organization": "Acme University",
	"organizationUnit": "SecOps"
}
$ step certificate create --template intermediate.tpl \
  --ca root_ca.crt --ca-key root_ca_key \
  --set-file organization.json --set organizationUnit=Biology \
  "Acme University Intermediate CA" intermediate_ca.crt intermediate_ca_key

The same is available on step certificate sign, which includes .Insecure.CR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants