mirror of
https://github.com/siderolabs/talos.git
synced 2026-05-05 04:16:21 +02:00
feat: support aws cert manager in imager
Add support for using certificates stored in AWS Certificate Manager to sign secureboot images in imager. Signed-off-by: Tim Jones <tim.jones@siderolabs.com>
This commit is contained in:
parent
4172095125
commit
4b274f7615
7
go.mod
7
go.mod
@ -51,6 +51,7 @@ require (
|
||||
github.com/alexflint/go-filemutex v1.3.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.6
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16
|
||||
github.com/aws/aws-sdk-go-v2/service/acm v1.37.19
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.49.4
|
||||
github.com/aws/smithy-go v1.24.0
|
||||
github.com/beevik/ntp v1.5.0
|
||||
@ -214,10 +215,10 @@ require (
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
|
||||
|
||||
14
go.sum
14
go.sum
@ -61,20 +61,22 @@ github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hC
|
||||
github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||
github.com/aws/aws-sdk-go-v2/service/acm v1.37.19 h1:6BPfgg/Y4Pmrdr8KDwHx2CYkw8qPEaGQ+aixjuAY/0U=
|
||||
github.com/aws/aws-sdk-go-v2/service/acm v1.37.19/go.mod h1:mhOStWeEa1xP99WNNPstX75qgqWgJycL5H7UwZQbqbo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
|
||||
|
||||
@ -111,11 +111,12 @@ type SigningKeyAndCertificate struct {
|
||||
AzureCertificateID string `yaml:"azureCertificateID,omitempty"`
|
||||
// AWS.
|
||||
//
|
||||
// AWS KMS Key ID and region.
|
||||
// AWS doesn't have a good way to store a certificate, so it's expected to be a file.
|
||||
// AWS KMS Key ID, ACM certificate ARN, and region.
|
||||
// Support local cert file for legacy use cases.
|
||||
AwsKMSKeyID string `yaml:"awsKMSKeyID,omitempty"`
|
||||
AwsRegion string `yaml:"awsRegion,omitempty"`
|
||||
AwsCertPath string `yaml:"awsCertPath,omitempty"`
|
||||
AwsCertARN string `yaml:"awsCertARN,omitempty"`
|
||||
}
|
||||
|
||||
// SigningKey describes a signing key.
|
||||
@ -159,6 +160,8 @@ func (keyAndCert SigningKeyAndCertificate) GetSigner(ctx context.Context) (pesig
|
||||
return file.NewSecureBootSigner(keyAndCert.CertPath, keyAndCert.KeyPath)
|
||||
case keyAndCert.AzureVaultURL != "" && keyAndCert.AzureCertificateID != "":
|
||||
return azure.NewSecureBootSigner(ctx, keyAndCert.AzureVaultURL, keyAndCert.AzureCertificateID, keyAndCert.AzureCertificateID)
|
||||
case keyAndCert.AwsKMSKeyID != "" && keyAndCert.AwsCertARN != "":
|
||||
return aws.NewSecureBootACMSigner(ctx, keyAndCert.AwsKMSKeyID, keyAndCert.AwsRegion, keyAndCert.AwsCertARN)
|
||||
case keyAndCert.AwsKMSKeyID != "" && keyAndCert.AwsCertPath != "":
|
||||
return aws.NewSecureBootSigner(ctx, keyAndCert.AwsKMSKeyID, keyAndCert.AwsRegion, keyAndCert.AwsCertPath)
|
||||
default:
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/acm"
|
||||
"github.com/aws/aws-sdk-go-v2/service/kms"
|
||||
)
|
||||
|
||||
@ -21,3 +22,12 @@ func getKmsClient(ctx context.Context, awsRegion string) (*kms.Client, error) {
|
||||
|
||||
return kms.NewFromConfig(awsCfg), nil
|
||||
}
|
||||
|
||||
func getAcmClient(ctx context.Context, awsRegion string) (*acm.Client, error) {
|
||||
awsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing AWS default config: %w", err)
|
||||
}
|
||||
|
||||
return acm.NewFromConfig(awsCfg), nil
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
for _, envVar := range []string{"AWS_KMS_KEY_ID", "AWS_REGION", "AWS_CERT_PATH"} {
|
||||
for _, envVar := range []string{"AWS_KMS_KEY_ID", "AWS_REGION", "AWS_CERT_PATH", "AWS_CERT_ARN"} {
|
||||
if os.Getenv(envVar) == "" {
|
||||
t.Skipf("%s not set", envVar)
|
||||
}
|
||||
@ -34,4 +34,10 @@ func TestIntegration(t *testing.T) {
|
||||
|
||||
_, err = sbSigner.Signer().Sign(nil, digest[:], nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
sbAcmSigner, err := aws.NewSecureBootACMSigner(t.Context(), os.Getenv("AWS_KMS_KEY_ID"), os.Getenv("AWS_REGION"), os.Getenv("AWS_CERT_ARN"))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sbAcmSigner.Signer().Sign(nil, digest[:], nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@ -12,6 +12,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/acm"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/secureboot/pesign"
|
||||
)
|
||||
|
||||
@ -61,3 +64,38 @@ func NewSecureBootSigner(ctx context.Context, kmsKeyID, awsRegion, certPath stri
|
||||
cert: cert,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewSecureBootACMSigner creates a new SecureBootSigner using an ACM certificate.
|
||||
func NewSecureBootACMSigner(ctx context.Context, kmsKeyID, awsRegion, acmCertificateARN string) (*SecureBootSigner, error) {
|
||||
keySigner, err := NewPCRSigner(ctx, kmsKeyID, awsRegion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize certificate key signer (kms): %w", err)
|
||||
}
|
||||
|
||||
acmClient, err := getAcmClient(ctx, awsRegion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build ACM client: %w", err)
|
||||
}
|
||||
|
||||
resp, err := acmClient.GetCertificate(ctx, &acm.GetCertificateInput{
|
||||
CertificateArn: &acmCertificateARN,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get certificate: %w", err)
|
||||
}
|
||||
|
||||
certBlock, _ := pem.Decode([]byte(pointer.SafeDeref(resp.Certificate)))
|
||||
if certBlock == nil {
|
||||
return nil, fmt.Errorf("failed to decode certificate")
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode certificate: %w", err)
|
||||
}
|
||||
|
||||
return &SecureBootSigner{
|
||||
keySigner: keySigner,
|
||||
cert: cert,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user