Rotate the encryption secrets on deploy (#1645)

This commit is contained in:
Ben Vesel 2021-12-01 05:14:11 -05:00 коммит произвёл GitHub
Родитель 222b479188
Коммит 2c04e7536d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 60 добавлений и 8 удалений

Просмотреть файл

@ -48,6 +48,7 @@ func deployKeyvaultAccessPolicy(_env env.Core) map[string]interface{} {
"objectId": os.Getenv("AZURE_SERVICE_PRINCIPAL_ID"),
"permissions": map[string]interface{}{
"secrets": []interface{}{
"Get",
"List",
"Set",
},

Просмотреть файл

@ -12,6 +12,7 @@ import (
"encoding/json"
"path/filepath"
"strings"
"time"
azkeyvault "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault"
mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
@ -24,6 +25,10 @@ import (
"github.com/Azure/ARO-RP/pkg/util/keyvault"
)
// Rotate the secret on every deploy of the RP iff the most recent
// secret is less than 3 days old
const rotateSecretAfter = time.Hour * 72
// PreDeploy deploys managed identity, NSGs and keyvaults, needed for main
// deployment
func (d *deployer) PreDeploy(ctx context.Context) error {
@ -390,11 +395,24 @@ func (d *deployer) configureServiceSecrets(ctx context.Context) error {
secretName string
len int
}{
{d.serviceKeyvault, env.EncryptionSecretName, 32},
{d.serviceKeyvault, env.EncryptionSecretV2Name, 64},
{d.serviceKeyvault, env.FrontendEncryptionSecretName, 32},
{d.serviceKeyvault, env.FrontendEncryptionSecretV2Name, 64},
{d.portalKeyvault, env.PortalServerSessionKeySecretName, 32},
} {
err := d.ensureAndRotateSecret(ctx, s.kv, s.secretName, s.len)
if err != nil {
return err
}
}
// don't rotate legacy secrets
for _, s := range []struct {
kv keyvault.Manager
secretName string
len int
}{
{d.serviceKeyvault, env.EncryptionSecretName, 32},
{d.serviceKeyvault, env.FrontendEncryptionSecretName, 32},
} {
err := d.ensureSecret(ctx, s.kv, s.secretName, s.len)
if err != nil {
@ -405,6 +423,32 @@ func (d *deployer) configureServiceSecrets(ctx context.Context) error {
return d.ensureSecretKey(ctx, d.portalKeyvault, env.PortalServerSSHKeySecretName)
}
func (d *deployer) ensureAndRotateSecret(ctx context.Context, kv keyvault.Manager, secretName string, len int) error {
existingSecrets, err := kv.GetSecrets(ctx)
if err != nil {
return err
}
for _, secret := range existingSecrets {
if filepath.Base(*secret.ID) == secretName {
latestVersion, err := kv.GetSecret(ctx, secretName)
if err != nil {
return err
}
updatedTime := time.Unix(0, latestVersion.Attributes.Created.Duration().Nanoseconds()).Add(rotateSecretAfter)
// do not create a secret if rotateSecretAfter time has
// not elapsed since the secret version's creation timestamp
if time.Now().Before(updatedTime) {
return nil
}
}
}
return d.createSecret(ctx, kv, secretName, len)
}
func (d *deployer) ensureSecret(ctx context.Context, kv keyvault.Manager, secretName string, len int) error {
existingSecrets, err := kv.GetSecrets(ctx)
if err != nil {
@ -417,8 +461,12 @@ func (d *deployer) ensureSecret(ctx context.Context, kv keyvault.Manager, secret
}
}
return d.createSecret(ctx, kv, secretName, len)
}
func (d *deployer) createSecret(ctx context.Context, kv keyvault.Manager, secretName string, len int) error {
key := make([]byte, len)
_, err = rand.Read(key)
_, err := rand.Read(key)
if err != nil {
return err
}

Просмотреть файл

@ -58,10 +58,16 @@ func TestAES256SHA512Open(t *testing.T) {
},
{
name: "invalid - encrypted value tampered with",
key: []byte("\x6a\x98\x95\x6b\x2b\xb2\x7e\xfd\x1b\x68\xdf\x5c\x40\xc3\x4f\x8b\xcf\xff\xe8\x17\xc2\x2d\xf6\x40\x2e\x5a\xb0\x15\x63\x4a\x2d\x2e\xab\x79\x86\x50\xfb\xce\xdc\x9d\xdd\x1c\x01\x32\xd6\x03\x99\xe6\x59\x81\x37\xb3\xdb\x67\x6f\x12\x34\x1d\xb9\x58\x18\x31\x30\x57"),
key: []byte("\x98\x98\x95\x6b\x2b\xb2\x7e\xfd\x1b\x68\xdf\x5c\x40\xc3\x4f\x8b\xcf\xff\xe8\x17\xc2\x2d\xf6\x40\x2e\x5a\xb0\x15\x63\x4a\x2d\x2e\xab\x79\x86\x50\xfb\xce\xdc\x9d\xdd\x1c\x01\x32\xd6\x03\x99\xe6\x59\x81\x37\xb3\xdb\x67\x6f\x12\x34\x1d\xb9\x58\x18\x31\x30\x57"),
input: []byte("\xda\x1c\x3c\x05\xb2\xf3\xc5\x93\x20\x9f\x9b\x67\x43\x8c\x0c\x3d\xe0\x80\x26\x59\x2a\x20\xb2\xe5\x5e\x30\xd6\xd1\x24\x1e\x34\x36\xbe\xfb\x79\x8e\x46\xb5\x95\xce\xe0\x79\x9c\x44\x5c\xaa\x83\x26\x92\xdb\x76\x34\x33\xe0\x0e\x0e\x54\xb2\x0b\x2f\xde\x63\x53\xf6"),
wantErr: "message authentication failed",
},
{
name: "invalid - encryption doesn't match input",
key: []byte("\x56\xd9\xb1\xa1\xc0\x4f\x7e\xf8\xbe\xd0\xd9\xb6\x16\xf1\x90\x84\x6b\x8e\x93\x98\x5e\xd2\x48\xf0\xc5\x60\xa0\x13\x3a\x0a\x7d\x7f\xb2\x20\xbd\x4b\x1c\x49\xab\xc5\xa7\x71\x6d\x17\xd9\xa8\x4a\x20\xec\xab\x05\x0d\x3c\xfc\x57\x0b\x5a\x4e\x63\x43\x27\x0c\xad\x6d"),
input: []byte("\xd9\x1c\x3c\x05\xb2\xf3\xc5\x93\x20\x9f\x9b\x67\x43\x8c\x0c\x3d\xe0\x80\x26\x59\x2a\x20\xb2\xe5\x5e\x30\xd6\xd1\x24\x1e\x34\x36\xbe\xfb\x79\x8e\x46\xb5\x95\xce\xe0\x79\x9c\x44\x5c\xaa\x83\x26\x92\xdb\x76\x34\x33\xe0\x0e\x0e\x54\xb2\x0b\x2f\xde\x63\x53\xf6"),
wantErr: "message authentication failed",
},
{
name: "invalid - too short",
key: []byte("\x6a\x98\x95\x6b\x2b\xb2\x7e\xfd\x1b\x68\xdf\x5c\x40\xc3\x4f\x8b\xcf\xff\xe8\x17\xc2\x2d\xf6\x40\x2e\x5a\xb0\x15\x63\x4a\x2d\x2e\xab\x79\x86\x50\xfb\xce\xdc\x9d\xdd\x1c\x01\x32\xd6\x03\x99\xe6\x59\x81\x37\xb3\xdb\x67\x6f\x12\x34\x1d\xb9\x58\x18\x31\x30\x57"),

Просмотреть файл

@ -12,10 +12,7 @@ func (fakeAEAD) Open(in []byte) ([]byte, error) {
}
func (fakeAEAD) Seal(in []byte) ([]byte, error) {
out := make([]byte, 4+len(in))
copy(out, fakeCode)
copy(out[4:], in)
return out, nil
return append(fakeCode, in...), nil
}
func NewFakeAEAD() *fakeAEAD {