Skip to content

Commit

Permalink
feat: dnssec load keys from AWS Secrets Manager
Browse files Browse the repository at this point in the history
Signed-off-by: kcolemangt <20099734+kcolemangt@users.noreply.github.com>
  • Loading branch information
kcolemangt committed Apr 16, 2024
1 parent 8de4531 commit 70a33a7
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 1 deletion.
14 changes: 14 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ require (
github.com/antonmedv/expr v1.15.5
github.com/apparentlymart/go-cidr v1.1.0
github.com/aws/aws-sdk-go v1.51.16
github.com/aws/aws-sdk-go-v2/config v1.27.11
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6
github.com/coredns/caddy v1.1.1
github.com/dnstap/golang-dnstap v0.4.0
github.com/farsightsec/golang-framestream v0.3.0
Expand Down Expand Up @@ -58,6 +60,18 @@ require (
github.com/DataDog/go-tuf v1.0.2-0.5.2 // indirect
github.com/DataDog/sketches-go v1.4.2 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
Expand Down
28 changes: 28 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,34 @@ github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4t
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
github.com/aws/aws-sdk-go v1.51.16 h1:vnWKK8KjbftEkuPX8bRj3WHsLy1uhotn0eXptpvrxJI=
github.com/aws/aws-sdk-go v1.51.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA=
github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE=
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs=
github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6 h1:TIOEjw0i2yyhmhRry3Oeu9YtiiHWISZ6j/irS1W3gX4=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6/go.mod h1:3Ba++UwWd154xtP4FRX5pUK3Gt4up5sDHCve6kVfE+g=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down
29 changes: 28 additions & 1 deletion plugin/dnssec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This plugin can only be used once per Server Block.

~~~
dnssec [ZONES... ] {
key file KEY...
key file|secret KEY...
cache_capacity CAPACITY
}
~~~
Expand Down Expand Up @@ -49,6 +49,22 @@ used.
* generated public key `Kexample.org+013+45330.key`
* generated private key `Kexample.org+013+45330.private`

* `key secret` indicates that **KEY** secret(s) should be read from AWS Secrets Manager. Secret names or
ARNs may be used. After generating the keys as described in the `key file` section, you can store them
in AWS Secrets Manager using the following AWS CLI v2 command:

```sh
aws secretsmanager create-secret --name "Kexample.org.+013+45330" \
--description "DNSSEC keys for example.org" \
--secret-string "$(jq -n --arg key "$(cat Kexample.org.+013+45330.key)" \
--arg private "$(cat Kexample.org.+013+45330.private)" \
'{key: $key, private: $private}')"
```

This command reads the contents of the `.key` and `.private` files, constructs a JSON object, and stores it
as a new secret in AWS Secrets Manager with the specified name and description. CoreDNS will then fetch
the key data from AWS Secrets Manager when using the `key secret` directive.

* `cache_capacity` indicates the capacity of the cache. The dnssec plugin uses a cache to store
RRSIGs. The default for **CAPACITY** is 10000.

Expand All @@ -75,6 +91,17 @@ example.org {
}
~~~

Sign responses for `example.org` with the key stored in AWS Secrets Manager under the secret name "Kexample.org.+013+45330".

~~~ corefile
example.org {
dnssec {
key secret Kexample.org.+013+45330
}
whoami
}
~~~

Sign responses for a kubernetes zone with the key "Kcluster.local+013+45129.key".

~~~
Expand Down
74 changes: 74 additions & 0 deletions plugin/dnssec/dnskey.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package dnssec

import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"encoding/json"
"errors"
"os"
"path/filepath"
"strings"
"time"

"github.com/coredns/coredns/request"

"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
"github.com/miekg/dns"
"golang.org/x/crypto/ed25519"
)
Expand All @@ -23,6 +28,12 @@ type DNSKEY struct {
tag uint16
}

// SecretKeyData represents the structure of the DNS keys stored in AWS Secrets Manager.
type SecretKeyData struct {
Key string `json:"key"`
Private string `json:"private"`
}

// ParseKeyFile read a DNSSEC keyfile as generated by dnssec-keygen or other
// utilities. It adds ".key" for the public key and ".private" for the private key.
func ParseKeyFile(pubFile, privFile string) (*DNSKEY, error) {
Expand Down Expand Up @@ -63,6 +74,69 @@ func ParseKeyFile(pubFile, privFile string) (*DNSKEY, error) {
return &DNSKEY{K: dk, D: dk.ToDS(dns.SHA256), s: nil, tag: 0}, errors.New("no private key found")
}

// ParseKeySecret retrieves and parses a DNSSEC key pair from AWS Secrets Manager.
func ParseKeySecret(secretID string) (*DNSKEY, error) {
// Load the AWS SDK configuration
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
return nil, err
}

// Create a Secrets Manager client
client := secretsmanager.NewFromConfig(cfg)

// Retrieve the secret value
input := &secretsmanager.GetSecretValueInput{
SecretId: &secretID,
}
result, err := client.GetSecretValue(context.TODO(), input)
if err != nil {
return nil, err
}

// Parse the secret string into SecretKeyData
var secretData SecretKeyData
err = json.Unmarshal([]byte(*result.SecretString), &secretData)
if err != nil {
return nil, err
}

// Parse the public key
rr, err := dns.NewRR(secretData.Key)
if err != nil {
return nil, err
}
dk, ok := rr.(*dns.DNSKEY)
if !ok {
return nil, errors.New("invalid public key format")
}

// Parse the private key
p, err := dk.ReadPrivateKey(strings.NewReader(secretData.Private), secretID)
if err != nil {
return nil, err
}

// Create the DNSKEY structure
var s crypto.Signer
var tag uint16
switch key := p.(type) {
case *rsa.PrivateKey:
s = key
tag = dk.KeyTag()
case *ecdsa.PrivateKey:
s = key
tag = dk.KeyTag()
case ed25519.PrivateKey:
s = key
tag = dk.KeyTag()
default:
return nil, errors.New("unsupported key type")
}

return &DNSKEY{K: dk, D: dk.ToDS(dns.SHA256), s: s, tag: tag}, nil
}

// getDNSKEY returns the correct DNSKEY to the client. Signatures are added when do is true.
func (d Dnssec) getDNSKEY(state request.Request, zone string, do bool, server string) *dns.Msg {
keys := make([]dns.RR, len(d.keys))
Expand Down
13 changes: 13 additions & 0 deletions plugin/dnssec/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ func keyParse(c *caddy.Controller) ([]*DNSKEY, error) {
}
keys = append(keys, k)
}
} else if value == "secret" {
ks := c.RemainingArgs()
if len(ks) == 0 {
return nil, c.ArgErr()
}

for _, k := range ks {
k, err := ParseKeySecret(k)
if err != nil {
return nil, err
}
keys = append(keys, k)
}
}
return keys, nil
}

0 comments on commit 70a33a7

Please sign in to comment.