feat: dnssec load keys from AWS Secrets Manager (#6618)

feat: dnssec load keys from AWS Secrets Manager
Signed-off-by: kcolemangt <20099734+kcolemangt@users.noreply.github.com>
This commit is contained in:
Keith Coleman
2024-10-24 14:50:04 -04:00
committed by GitHub
parent 04d00b0083
commit 7078f1576f
5 changed files with 170 additions and 1 deletions

View File

@@ -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"
)
@@ -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) {
@@ -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")
}
// ParseKeyFromAWSSecretsManager retrieves and parses a DNSSEC key pair from AWS Secrets Manager.
func ParseKeyFromAWSSecretsManager(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))