Skip to content

Instantly share code, notes, and snippets.

@dch
Last active June 23, 2025 16:06
Show Gist options
  • Save dch/7800b63c5c79a617d6ea62d5eca6bd3e to your computer and use it in GitHub Desktop.
Save dch/7800b63c5c79a617d6ea62d5eca6bd3e to your computer and use it in GitHub Desktop.
DNSSEC RR tools - use zonekeys <zone> to create the KSK that is published into the parent zone as DS RR
function zonekeys
set -l type rsa
set -l algo 8
set -l zone $argv[1]
test -d $zone || mkdir $zone
cd $zone
# generate keys if missing
test -s $zone-old.pem || ln -s canonical/51186.rsa1024.pem $zone-old.pem
test -s $zone-ksk.pem || brssl skey -gen $type:1024 -rawpem $zone-ksk.pem
test -s $zone-zsk.pem || brssl skey -gen $type:2048 -rawpem $zone-zsk.pem
# generate parent zone DS record
echo -n OLD:
ds $zone. $zone-old.pem | tee $zone.parent.zone
echo -n KSK:
ds $zone. $zone-ksk.pem | tee -a $zone.parent.zone
# extract tags from DS record
set -l old_tag (ds $zone. $zone-old.pem | cut -wf 4)
set -l ksk_tag (ds $zone. $zone-ksk.pem | cut -wf 4)
# ds(1) always expects a KSK, so -1 to fix that
set -l zsk_tag (math (ds $zone. $zone-zsk.pem | cut -wf 4) -1)
# generate our DNSKEY records
set -l old (dnskey -k $zone. $zone-old.pem | tee $zone.zone)
set -l ksk (dnskey -k $zone. $zone-ksk.pem | tee -a $zone.zone)
set -l zsk (dnskey $zone. $zone-zsk.pem | tee -a $zone.zone)
# prepare JSON RR for adding to zone.json
jq -n \
--arg zone $zone \
--argjson algo $algo \
--arg ksk (echo $old | cut -wf 7) \
--argjson tag $old_tag \
'{name:$zone,type:"DNSKEY",ttl:10800,data:{flags:257,protocol:3,alg:$algo,public_key:$ksk,key_tag:$tag}}' \
| tee -a $zone.json
jq -n \
--arg zone $zone \
--argjson algo $algo \
--arg ksk (echo $ksk | cut -wf 7) \
--argjson tag $ksk_tag \
'{name:$zone,type:"DNSKEY",ttl:10800,data:{flags:257,protocol:3,alg:$algo,public_key:$ksk,key_tag:$tag}}' \
| tee -a $zone.json
jq -n \
--arg zone $zone \
--argjson algo $algo \
--arg zsk (echo $zsk | cut -wf 7) \
--argjson tag $zsk_tag \
'{name:$zone,type:"DNSKEY",ttl:10800,data:{flags:256,protocol:3,alg:$algo,public_key:$zsk,key_tag:$tag}}' \
| tee -a $zone.json
# generate keys to prepend to JSON records field
jq -Rn '{inception: "2020-02-01T11:11:11.123456Z", until: "2040-02-01T11:11:11.123456Z" }' \
> $zone.keys
jq \
--argjson algo $algo \
--argjson tag $ksk_tag \
-Rs '{ksk_keytag: $tag, ksk_alg: $algo, ksk:.}' $zone-ksk.pem >> $zone.keys
jq \
--argjson algo $algo \
--argjson tag $zsk_tag \
-Rs '{zsk_keytag: $tag, zsk_alg: $algo, zsk:.}' $zone-zsk.pem >> $zone.keys
jq -Ss '{keys:[.[0] * .[1] * .[2]]}' $zone.keys
cd -
end
dch@wintermute /r/d/test> zonekeys koan-ci.com
OLD:koan-ci.com.        IN      DS      51186 8 2 4309ebd42a533bb0d4efe8504afe1fd55c675d9263fc912543cc4c1ca485653e
KSK:koan-ci.com.        IN      DS      2058 8 2 7e6e7d091631c23ecee59ee3fb7e569e035f02d59498c03cd8867419fa24ce5e
{
  "name": "koan-ci.com",
  "type": "DNSKEY",
  "ttl": 10800,
  "data": {
    "flags": 257,
    "protocol": 3,
    "alg": 8,
    "public_key": "AQPHNqSYNk+N2dbDk3a0t27g2cn0qvEX/YLajPXkBJ62t1w74gSrpw36FIXYqHTsxvLfJOulrayKtzP3MRaxn6V/wx+D/JM6quW/tR/jcAppGR8xwwaLtbdXGzMHeaNZf9976JWYV4ZozYRNlHC43fkbGEx5ImIHsX5JBekrZfJZMQ==",
    "key_tag": 51186
  }
}
{
  "name": "koan-ci.com",
  "type": "DNSKEY",
  "ttl": 10800,
  "data": {
    "flags": 257,
    "protocol": 3,
    "alg": 8,
    "public_key": "AQPCSeab1DvF3gdwejIvUSgG4oY7ZNIVqfnu9el6nKcnsogLRIY2ZLdozuyApGz80bn0lt4iicv0TK1N8yvFeMz068aLGO2WYrQ6zkytyl9O/8y4BzVE4dpOQHgg2vsc8rbZkIbpRF5ZIvJItkWb2IdCTcu4w5Mg+TdbjsNZY09a0Q==",
    "key_tag": 2058
  }
}
{
  "name": "koan-ci.com",
  "type": "DNSKEY",
  "ttl": 10800,
  "data": {
    "flags": 256,
    "protocol": 3,
    "alg": 8,
    "public_key": "AQPFTct82yg/VMJXklitPM3YpcxRmKk5/0aLPrTj5SoHQQJN6rCWnpzVorr9ICGfe4u5XHwZPmtJZt9C8UDryP7M0Ze/LkZhoW1glzu+g39zubqH/N6ba6nEv6622ZeerwPPu583tb3a5dhrR1iu18hfK8vZkp5TH7DB40urZNiP41I6j5WsVWxtN+9RT+EFJ+Df03vE91p/IDy+zIXwML1+hrQuoG9zZlezeMsW/8/9KYcs9dOabMTgTOPlC7zkeD+NAZtnoyljchyw2KbV1tCTBlrP+BEDxI/1hm6PRLKoKg0kY6exOuGyCC1ovtJHz3lS3U9wocOwKehYTP/XsVLd",
    "key_tag": 54908
  }
}
{
  "keys": [
    {
      "inception": "2020-02-01T11:11:11.123456Z",
      "zsk": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...5ZXhVoMA==\n-----END RSA PRIVATE KEY-----\n",
      "ksk_alg": 8,
      "ksk_keytag": 2058,
      "until": "2040-02-01T11:11:11.123456Z",
      "zsk": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...5ZXhVoMA==\n-----END RSA PRIVATE KEY-----\n",
      "zsk_alg": 8,
      "zsk_keytag": 54908
    }
  ]
}
function zonesign
set -l zone $argv[1]
# use general keys
test -s $zone-ksk.pem || ln -s cabal5.net-ksk.pem $zone-ksk.pem
test -s $zone-zsk.pem || ln -s cabal5.net-zsk.pem $zone-zsk.pem
# generate parent zone DS record
echo -n KSK:
ds $zone. $zone-ksk.pem | tee $zone.parent.zone
echo -n ZSK:
ds $zone. $zone-zsk.pem | tee -a $zone.parent.zone
# generate our DNSKEY records
set -l ksk (dnskey -k $zone. $zone-ksk.pem | tee $zone.zone)
set -l zsk (dnskey $zone. $zone-zsk.pem | tee -a $zone.zone)
# prepare JSON RR for adding to zone.json
jq -n \
--arg zone $zone \
--arg ksk (echo $ksk | cut -wf 7) \
'{name:$zone,type:"DNSKEY",ttl:120,data:{flags:257,protocol:3,alg:8,public_key:$ksk,key_tag:0}}' \
| tee $zone.json
jq -n \
--arg zone $zone \
--arg zsk (echo $zsk | cut -wf 7) \
'{name:$zone,type:"DNSKEY",ttl:120,data:{flags:256,protocol:3,alg:8,public_key:$zsk,key_tag:0}}' \
| tee -a $zone.json
# generate keys to prepend to JSON records field
jq -Rn '{inception: "2020-08-14T11:36:58.851612Z", until: "2023-02-12T11:36:58.849384Z" }' \
> $zone.keys
jq -Rs '{ksk_keytag: 0, ksk_alg: 8, ksk:.}' $zone-ksk.pem >> $zone.keys
jq -Rs '{zsk_keytag: 0, zsk_alg: 8, zsk:.}' $zone-zsk.pem >> $zone.keys
jq -Ss '{keys:[.[0] * .[1] * .[2]]}' $zone.keys
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment