From 2b56d4e675375669f1962b173c2d9816c3177a91 Mon Sep 17 00:00:00 2001 From: Julian Sommer <115516918+juliansommer@users.noreply.github.com> Date: Tue, 29 Sep 2026 15:19:41 +1000 Subject: [PATCH] fix: reject KeyFormat=ppk on CreateKeyPair rather than silently returning a PEM --- spinifex/handlers/ec2/key/service_impl.go | 14 +++++++++ .../handlers/ec2/key/service_impl_test.go | 30 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/spinifex/handlers/ec2/key/service_impl.go b/spinifex/handlers/ec2/key/service_impl.go index 9f2a14e5c..448d0386e 100644 --- a/spinifex/handlers/ec2/key/service_impl.go +++ b/spinifex/handlers/ec2/key/service_impl.go @@ -151,6 +151,20 @@ func (s *KeyServiceImpl) CreateKeyPair(ctx context.Context, input *ec2.CreateKey } } + // A declared divergence: AWS returns a PuTTY key for ppk, Spinifex refuses + // it rather than silently returning a PEM the caller did not ask for. + if input.KeyFormat != nil { + switch *input.KeyFormat { + case ec2.KeyFormatPem: + case ec2.KeyFormatPpk: + return nil, awserrors.Errorf(awserrors.ErrorInvalidParameterValue, + "The ppk key format is not supported; use pem.") + default: + return nil, awserrors.Errorf(awserrors.ErrorInvalidParameterValue, + "1 validation error detected: Value '%s' at 'keyFormat' failed to satisfy constraint: Member must satisfy enum value set: [pem, ppk]", *input.KeyFormat) + } + } + // Generate the key in process; the private half never reaches local disk. privateKeyData, publicKey, err := generateKeyPair(keyType) if err != nil { diff --git a/spinifex/handlers/ec2/key/service_impl_test.go b/spinifex/handlers/ec2/key/service_impl_test.go index 66c495bad..c54c7fe84 100644 --- a/spinifex/handlers/ec2/key/service_impl_test.go +++ b/spinifex/handlers/ec2/key/service_impl_test.go @@ -270,6 +270,36 @@ func TestCreateKeyPair_InvalidKeyType(t *testing.T) { assert.Equal(t, "1 validation error detected: Value 'dsa' at 'keyType' failed to satisfy constraint: Member must satisfy enum value set: [rsa, ed25519]", msg) } +func TestCreateKeyPair_KeyFormat(t *testing.T) { + svc, store := newTestKeyService() + + for _, tc := range []struct { + format, msg string + }{ + {"ppk", "The ppk key format is not supported; use pem."}, + {"der", "1 validation error detected: Value 'der' at 'keyFormat' failed to satisfy constraint: Member must satisfy enum value set: [pem, ppk]"}, + } { + out, err := svc.CreateKeyPair(context.Background(), &ec2.CreateKeyPairInput{ + KeyName: aws.String("fmt-" + tc.format), + KeyFormat: aws.String(tc.format), + }, testAccountID) + assert.Nil(t, out) + code, msg, ok := awserrors.ResolveErrorDetail(err) + require.True(t, ok) + assert.Equal(t, awserrors.ErrorInvalidParameterValue, code) + assert.Equal(t, tc.msg, msg) + } + assert.Zero(t, store.Count(), "a rejected format must not store a key") + + out, err := svc.CreateKeyPair(context.Background(), &ec2.CreateKeyPairInput{ + KeyName: aws.String("fmt-pem"), + KeyFormat: aws.String("pem"), + KeyType: aws.String("rsa"), + }, testAccountID) + require.NoError(t, err) + assert.True(t, strings.HasPrefix(*out.KeyMaterial, "-----BEGIN RSA PRIVATE KEY-----")) +} + // ============================================================ // ImportKeyPair Tests // ============================================================