[Freeipa-devel] DNSSEC support design considerations: key material handling

Simo Sorce simo at redhat.com
Wed Jul 17 16:25:20 UTC 2013


On Tue, 2013-07-16 at 17:15 +0200, Petr Spacek wrote:
> On 15.7.2013 21:07, Simo Sorce wrote:
> > Is there any place I can read about the format and requirements of these
> > files ?
> There is no single format, because it is algorithm-dependent. See below. AFAIK 
> it is nothing supported by OpenSSL, but I can be wrong.

Thanks for attaching examples, it helps.

> >> KSK has to be rolled over manually because it requires changes in parent zone.
> >> (It could be automated for sub-zones if their parent zone is also managed by
> >> the same IPA server.)
> >
> > Is there any provision for using DNSSEC with private DNS deployments ?
> Yes, it is. DNSSEC supports 'Islands of Security' [Terminology]: DNS resolvers 
> can be configured with 'trust anchors' explicitly. E.g. 'trust domain 
> example.com only if it is signed by /this/ key, use root key for rest of the 
> Internet' etc.
> 
> [Terminology] http://tools.ietf.org/html/rfc4033#section-2

This means clients would have to be configured to explicitly trust a
specific key for a zone right ? How hard would it be for us to configure
IPA clients this way assuming by then we have a DNSSEC aware resolver we
can configure on them ?

> > Or is this going to make sense only for IPA deployments that have valid
> > delegation from the public DNS system ?
> >
> > Hmmm I guess that as long as the KSK in the 'parent' zone is imported
> > properly a private deployment of corp.myzone.com using the KSK of
> > myzone.com will work just fine even if corp.myzone.com is not actually
> > delegated but is a private DNS tree ?
> > Or is that incorrect ?
> 
> AFAIK there *has to be* delegation via DS record [Delegation Signer, DS] from 
> the parent, but IMHO it could work if only the public key for internal zones 
> is published (without any delegation to internal name servers etc.). I didn't 
> try it, so 'here be dragons'.

Are there test/zones keys that can be used to experiment ?

[..]

> >> Initial key generation is closely related to the question how should we handle
> >> (periodic) key regeneration? (e.g. "Generate new ZSK each month.")
> >
> > We only really need to generate (or import) the KSK of the parent zone,
> It seems that there is slight misunderstanding. KSK is the 'master key' for 
> particular zone. This master key (KSK) signs other keys (ZSKs) and data are 
> signed by ZSKs.

Sorry I expressed myself badly, I mean we only need to generate one KSK
at install time and make it available to the admin to be signed by the
upper zone admins. But then all other keys including the ZSKs can be
completely managed within IPA w/o explicit admin work if we have the
right tooling.

[..]

> > No, the problem is that we need to define 'who' generates the keys.
> > Remember FreeIPA is a multimaster system, we cannot have potentially
> > conflicting cron jobs running on multiple servers.
> Right. It sounds like the CRL generation problem. Should we do the same for 
> DNSSEC key regeneration? I.e. select one super-master and let it to handle key 
> regeneration? Or should we find some more robust solution? I'm not against any 
> of these possibilities :-)

Falling back to SPOF should be the last resort or a temporary step
during development.
I would like to avoid SPOF architectures if at all possible.
We could devise a way to automatically 'elect' a master, but have all
other DNS servers also monitor that keys are regenerated an made
available in the expected time frame and if not have one of the other
DNS servers try to assume the leader role.

I have some ideas hear using priorities etc, but I need to let them brew
in my mind a little bit more :)

[..]

> >> For these reasons I think that we can define new public key attribute in the
> >> same way as private key attribute:
> >> attributetypes: ( x.x.x.x.x NAME 'idnsSecPublicKey' SYNTAX
> >> 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
> >>
> >> The resulting object class could be:
> >> objectClasses: ( x.x.x.x.x NAME 'idnsSecKeyPair' DESC 'DNSSEC key pair' SUP
> >> top STRUCTURAL MUST ( cn $ idnsSecPrivateKey $ idnsSecPublicKey ) )
> >
> > Will bind read these attributes ?
> > Or will we have to dump these values into files via bind-dyndb-ldap for
> > bind9 to read them back ?
> AFAIK it has to be in files: Private key in one file and public key in the 
> other file. I can't find any support for reading private keys from buffers.

Ok so to summarize we basically are going to load the private key file
in idnsSecPrivateKey and the public key file in idnsSecPublicKey as
blobs and the have bind-dyndb-ldap fetch them and save them into files
that bind can access.
This means bind-dyndb-ldap will need to grow the ability to also clean p
and synchronize the files over time. So there will need to be hooks to
regularly check all needed files are in place and obsolete ones are
deleted. Maybe we can grow a companion python helper to do this, as it
is a relatively simple task, that is not performance critical and will
be much easier to write in a scripting language than in C. But I am not
opposed to an in-daemon solution either.

[..]

> > ack, should we have an explicit attribute that tells us what type it
> > is ?
> May be, we will see. It is possible that we will need to store key algorithm 
> and key ID explicitly for some reason.
> 
> I'm still not sure that I understand to all aspects of key management in BIND.

Ok, so I guess we need some reasearch in here before committing 100% to
a plan, but so far it looks like the general plan is clear enough.

> > One weak reason to allow read by admins would be to allow them to
> > migrate away, but I do not like to put these keys completely unprotected
> > in LDAP. Given bind has a keytab I was thinking we may want to encrypt
> > these keys with the DNS long term key, however this complicates the code
> > slightly in 2 ways:
> > 1. we can have multiple DNS Servers (ie multiple keys)
> > 2. we need to allow for roll-over
> 
> I see two more problems:
> 3. it would make Kerberos required (now the plugin doesn't require Kerberos)

It could be optional, if the option is not enabled no master-key
encryption scheme is used.

> 4. we use SASL but I think that your approach would require direct 
> manipulation with keytab

Yes we'd need to read the keytab to get the long term key, but we could
defer this to a companion tool in python as I mentioned before and let
bind-dyndb-ldap ignorant of the keytab.
Actually this is a quite compelling argument, as this means we could use
gssproxy to not give access to the keytab at all to the bind process,
thus adding extra privilege seapration and protection, The python
companion would instea dneed access so communication between
bind-dyndb-ldap and the companion daemon would need to happen cross
trust boundary, ie a socket and/or systemd/dbus activation or similar.

> > To simplify the matter we would have to use a 'master key' that encrypts
> > all signing keys and is made available to DNS servers encrypted with
> > their keys.
> >
> > Master key needs to allow for roll over in case it is compromised. But
> > we could deal with it by simply rolling also all DNS keys and encrypting
> > the new ones with the new key. After all if the key was compromised we
> > must assume all DNs signing keys may have been compromised so a full
> > roll-over is necessary. This simplifies the problem because it means we
> > will never need to store the same DNS signing key encrypted with
> > multiple 'master keys'.
> >
> > A master key also allows for easy addition/removal of DNS servers as it
> > needs to be re-encrypted only once when a new DNS is added (or removed
> > and readded), and a server removal is just a delete operation.
> 
> Oooo, lots of fun. Are you aware of any abstraction layer which could all the 
> magic for us? Something from OpenSSL/SASL/GSSAPI? I didn't mention Dogtag 
> because dependency on Dogtag might become my nightmare... :-)

Not really, I think we may have to do our own, but we'll reuse what
NSS/OpenSSL or krb libraries make available to do wrapping on this stuff
so that we do not create some horrible easy to break scheme. 

[..]

> > Should we add these attributes explicitly in the 'idnsSecKeyPair'
> > objetclass instead and reconstruct the private key file from there ?
> > Or would that risk being incompatibile with a future new key type ?
> That is exactly why I proposed the 'blob' approach. Each algorithm needs 
> different values, so RSA and DSA key formats differ. See attachments - these 
> files were written by dnssec-keygen for RSASHA1 and DSA.
> 
> Formats are *similar* at the moment, but the problem is that parsers for each 
> algorithm can diverge in the future.

And blob it is ... sold! :)


> > If so should we really split key material in 2 attributes? Or should we
> > rather just load the full file content in a single attribute as an
> > opaque blob ?
> BIND 9 stores public and private keys separately in two files, so I would 
> imitate it's approach - with two separate attributes.

ok

> >> 3) How will the configuration be stored?
> >> Parameters are:
> >> - DNSSEC enabled/disabled for one zone or globally - proposal: add a new
> >> boolean attribute idnsSecInlineSigning to zone and global config object
> >
> > why not simply iDNSSECenabled: TRUE/FALSE ?
> I would like to imitate BIND's config - we plan to do the same thing as BIND's 
> option 'inline-signing'.

ok

> BIND will do signing for us, but at some point in the future we could decide 
> to do signing ourselves etc. More specific name prevents confusion when we 
> need to change behaviour.

makes sense

> >> - NSEC3 parameters - proposal: use standard NSEC3PARAM record in the zone
> >
> > What are these ?
> Short answer:
> http://www.simpledns.com/help/v52/rec_nsec3param.htm
> 
> Long answer:
> DNS Security (DNSSEC) Hashed Authenticated Denial of Existence
> http://tools.ietf.org/html/rfc5155#section-4

Interesting.

> >> The rest of the configuration options are related to the key management
> >> problem. We need to know:
> >> - how many key pairs (e.g. 2 KSKs, 2 ZSKs)
> >
> > Shouldn't we allow an arbitrary number ? Does bind have strict limits ?
> Yes, arbitrary number sounds fine. 2 + 2 was just an example.
> 
> >> - when (e.g. generate new key pair 30 days before active key expires)
> >
> > probably needs to be tunable. new attribute ?
> >
> >> - of which key types (KSK or ZSK)
> >> - with which algorithms
> >> - with which key lengths
> >> should be generated. Note that we need to store configuration about X KSKs and
> >> Y ZSKs.
> >
> > seem all of these needs to be tunables and require their own
> > attributes ?
> I agree. The question is how to group the attributes to make it useful.

ok

> IMHO it should express something like this:
> - I want to use 1 KSK with algorithm RSASHA1, key length 2048 bits, the key 
> should be used for 1 year.
> - I want to have 1 other KSK (with same parameters) ready for roll over at any 
> time.
> - Roll over period is 1 month. (The time required for incremental resigning 
> with the new key, i.e. the time period when old and new signatures will co-exist.)
> 
> The result should be:
> 
> In time 0 (zone creation), generate 2 KSKs:
> The KSK 'A' would have these timestamps:
> - created = published = active from = 0 (generate signatures immediately)
> - inactive = 0 + 1 year - 1 month (stop generating signatures after 11 months)
> - delete = 0 + 1 year (one month was transitional period for incremental 
> resigning with the new key, then delete the key 'A')
> 
> The KSK 'B' would be generated at the same time as 'A':
> - created = published = 0 (publish key, but don't generate signatures)
> - active from = 0 + 1 year
> - inactive = 0 + 2 years - 1 month
> - delete = 0 + 2 years
> 
> During the first year, all records will be signed with KSK 'A'. In time '0 + 1 
> year - 1 month' KSK 'A' will become inactive and KSK 'B' will become active. 
> At the same time, new KSK 'C' will be generated with following timestamps:
> - created = published = 1 year - 1 month (publish key, but don't generate 
> signatures)
> - active from = 0 + 2 year - 1 month
> - inactive = 0 + 3 years - 1 month
> - delete = 0 + 3 years
> 
> All records will be re-signed using KSK 'B' during time <1 year - 1 month, 1 
> year>.
> 
> In time  '0 + 1 year' all signatures were regenerated with using KSK 'B' and 
> KSK 'A' will be removed.

shouldn't we regenerate all signatures with KSK B at '0 + 11mo', ie 1
month before KSK A is finally deleted ?

> Note that you may want to use 1 KSK with algorithm RSA and another KSK with DSA.

Ok

> I'm not really sure if it makes sense. Could something like this work?
> 
> objectClasses: ( x.x.x.x.x NAME 'idnsSecKeyGroup' DESC 'DNSSEC key group' SUP 
> top STRUCTURAL MUST
> ( cn $
>    key type $ # (KSK or ZSK)
>    algorithm $ # (RSA, DSA)
>    key length $ # (2048)
>    lifetime of the key $ # (1 year)
>    roll over period $ # (1 month)
>    number of active keys $ # (1)
>    number of spare keys $ # (1)
>   ) )

To summarize it seem you have 2 distinctive objects you really need.

1. additional parameters to the key (active time and delete time, and
although those times are also embedded in the blob they should probably
be replicated also in idnsSecKeyPair objectclass so that this info can
be easily queried w/o needing access to the key material itself.

2. a policy about how often you want to rotate and use keys, and what
parameters to use by default when creating new keys automatically at
rotation time. And that policy may need to be per zone.

so 

I would rename 'idnsSecKeyGroup' to 'idnsSecKeyPolicy', make it
auxiliary and add it to the zone object when DNSSEc is in use.
The attributes you mention seem all is needed.

> The key group could be stored as
> cn=ksk-rsa, idsname=example.com, cn=dns, dc=ipa,dc=test
> Keys could be stored as individual objects under
> cn=id, cn=ksk-rsa, idsname=example.com, cn=dns, dc=ipa,dc=test

This is also an option, but why an aditional object when we can simply
ad the attributes to the zone file ?
Is there any instance where you might want multiple policies for zones?
(I do not see how that would work)

> In usual cases it solves grouping of KSKs and ZSKs.

Why do you need to further 'group' them ?

>  Also, it enables us to 
> define key group with RSA and another one with DSA algorithm or to migrate 
> from a key group with shorter keys to a key group with longer keys.

I am not sure how this would help, isn't is sufficient to add the 'type'
to 'idnsSecKeyPair', so you know what type it is regardless ? Although I
am not even sure why we would care, bind is the one doing the signing
and the type is already known to bind as it reads it from the private
file, right ?

I may be missing some detail here ...

[..]

> I have a crazy idea: Could OpenSSL PKCS#11 implementation help us to deal with 
> the key management problems mentioned above - somehow?
> 
> I know next to nothing about PKCS#11 and related areas, but problems we met 
> (like safe key storage & transport) sounds like something common.
> 
> Could we use PKCS#11 in some clever way, let OpenSSL to do the dirty work with 
> key encryption/retrieval and solve HSM support and security at once?

Yes we will certainly reuse crypto primitives from NSS or OpenSSL, but
that doesn't help with 'key management' itself, that's on us :)

> Would it be possible to write PKCS#11 module for OpenSSL and let it to store 
> keys in IPA - in some generic way? So it will solve key storage for all 
> OpenSSL/PKCS#11 enabled applications and not only for bind-dyndb-ldap?

Dogtag has a generic store, but a generic store is not really our
problem here. and I am not sure we want to tie this to dogtag, we might.

> As I said, it is just crazy idea ... and I really know nothing about this area.

Let's explore and see pros/cons.
, the main con I see to involving dogtag is that it would force us to
install dogtag on each DNS server (or risk having keys in a remote
server so net communicationa nd additional issues of reachability).

I think we want to be able to keep installing FreeIPA+DNS and FreeIPA+CA
and not force FreeIPa+DNS+CA for all DNS servers, as we might want a
'lightweight' FreeIPA+DNS replica or even in future just a LDAP+DNS
'replica' only for load balancing of DNSes, so forcing the full CA
dependency would be undesirable. Extreme case, given syncrepl will keep
everything synced locally we may even go with bind+bind-dyndb-ldap
*only* and rely on remote LDAP server to bind to ...

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York




More information about the Freeipa-devel mailing list