sse_kms_openbao_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package sse_test
  2. import (
  3. "bytes"
  4. "context"
  5. "io"
  6. "testing"
  7. "time"
  8. "github.com/aws/aws-sdk-go-v2/aws"
  9. "github.com/aws/aws-sdk-go-v2/service/s3"
  10. "github.com/aws/aws-sdk-go-v2/service/s3/types"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. )
  14. // TestSSEKMSOpenBaoIntegration tests SSE-KMS with real OpenBao KMS provider
  15. // This test verifies that SeaweedFS can successfully encrypt and decrypt data
  16. // using actual KMS operations through OpenBao, not just mock key IDs
  17. func TestSSEKMSOpenBaoIntegration(t *testing.T) {
  18. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  19. defer cancel()
  20. client, err := createS3Client(ctx, defaultConfig)
  21. require.NoError(t, err, "Failed to create S3 client")
  22. bucketName, err := createTestBucket(ctx, client, defaultConfig.BucketPrefix+"sse-kms-openbao-")
  23. require.NoError(t, err, "Failed to create test bucket")
  24. defer cleanupTestBucket(ctx, client, bucketName)
  25. t.Run("Basic SSE-KMS with OpenBao", func(t *testing.T) {
  26. testData := []byte("Hello, SSE-KMS with OpenBao integration!")
  27. objectKey := "test-openbao-kms-object"
  28. kmsKeyID := "test-key-123" // This key should exist in OpenBao
  29. // Upload object with SSE-KMS
  30. putResp, err := client.PutObject(ctx, &s3.PutObjectInput{
  31. Bucket: aws.String(bucketName),
  32. Key: aws.String(objectKey),
  33. Body: bytes.NewReader(testData),
  34. ServerSideEncryption: types.ServerSideEncryptionAwsKms,
  35. SSEKMSKeyId: aws.String(kmsKeyID),
  36. })
  37. require.NoError(t, err, "Failed to upload SSE-KMS object with OpenBao")
  38. assert.NotEmpty(t, aws.ToString(putResp.ETag), "ETag should be present")
  39. // Retrieve and verify object
  40. getResp, err := client.GetObject(ctx, &s3.GetObjectInput{
  41. Bucket: aws.String(bucketName),
  42. Key: aws.String(objectKey),
  43. })
  44. require.NoError(t, err, "Failed to retrieve SSE-KMS object")
  45. defer getResp.Body.Close()
  46. // Verify content matches (this proves encryption/decryption worked)
  47. retrievedData, err := io.ReadAll(getResp.Body)
  48. require.NoError(t, err, "Failed to read retrieved data")
  49. assert.Equal(t, testData, retrievedData, "Decrypted data should match original")
  50. // Verify SSE-KMS headers are present
  51. assert.Equal(t, types.ServerSideEncryptionAwsKms, getResp.ServerSideEncryption, "Should indicate KMS encryption")
  52. assert.Equal(t, kmsKeyID, aws.ToString(getResp.SSEKMSKeyId), "Should return the KMS key ID used")
  53. })
  54. t.Run("Multiple KMS Keys with OpenBao", func(t *testing.T) {
  55. testCases := []struct {
  56. keyID string
  57. data string
  58. objectKey string
  59. }{
  60. {"test-key-123", "Data encrypted with test-key-123", "object-key-123"},
  61. {"seaweedfs-test-key", "Data encrypted with seaweedfs-test-key", "object-seaweedfs-key"},
  62. {"high-security-key", "Data encrypted with high-security-key", "object-security-key"},
  63. }
  64. for _, tc := range testCases {
  65. t.Run("Key_"+tc.keyID, func(t *testing.T) {
  66. testData := []byte(tc.data)
  67. // Upload with specific KMS key
  68. _, err := client.PutObject(ctx, &s3.PutObjectInput{
  69. Bucket: aws.String(bucketName),
  70. Key: aws.String(tc.objectKey),
  71. Body: bytes.NewReader(testData),
  72. ServerSideEncryption: types.ServerSideEncryptionAwsKms,
  73. SSEKMSKeyId: aws.String(tc.keyID),
  74. })
  75. require.NoError(t, err, "Failed to upload with KMS key %s", tc.keyID)
  76. // Retrieve and verify
  77. getResp, err := client.GetObject(ctx, &s3.GetObjectInput{
  78. Bucket: aws.String(bucketName),
  79. Key: aws.String(tc.objectKey),
  80. })
  81. require.NoError(t, err, "Failed to retrieve object encrypted with key %s", tc.keyID)
  82. defer getResp.Body.Close()
  83. retrievedData, err := io.ReadAll(getResp.Body)
  84. require.NoError(t, err, "Failed to read data for key %s", tc.keyID)
  85. // Verify data integrity (proves real encryption/decryption occurred)
  86. assert.Equal(t, testData, retrievedData, "Data should match for key %s", tc.keyID)
  87. assert.Equal(t, tc.keyID, aws.ToString(getResp.SSEKMSKeyId), "Should return correct key ID")
  88. })
  89. }
  90. })
  91. t.Run("Large Data with OpenBao KMS", func(t *testing.T) {
  92. // Test with larger data to ensure chunked encryption works
  93. testData := generateTestData(64 * 1024) // 64KB
  94. objectKey := "large-openbao-kms-object"
  95. kmsKeyID := "performance-key"
  96. // Upload large object with SSE-KMS
  97. _, err := client.PutObject(ctx, &s3.PutObjectInput{
  98. Bucket: aws.String(bucketName),
  99. Key: aws.String(objectKey),
  100. Body: bytes.NewReader(testData),
  101. ServerSideEncryption: types.ServerSideEncryptionAwsKms,
  102. SSEKMSKeyId: aws.String(kmsKeyID),
  103. })
  104. require.NoError(t, err, "Failed to upload large SSE-KMS object")
  105. // Retrieve and verify large object
  106. getResp, err := client.GetObject(ctx, &s3.GetObjectInput{
  107. Bucket: aws.String(bucketName),
  108. Key: aws.String(objectKey),
  109. })
  110. require.NoError(t, err, "Failed to retrieve large SSE-KMS object")
  111. defer getResp.Body.Close()
  112. retrievedData, err := io.ReadAll(getResp.Body)
  113. require.NoError(t, err, "Failed to read large data")
  114. // Use MD5 comparison for large data
  115. assertDataEqual(t, testData, retrievedData, "Large encrypted data should match original")
  116. assert.Equal(t, kmsKeyID, aws.ToString(getResp.SSEKMSKeyId), "Should return performance key ID")
  117. })
  118. }
  119. // TestSSEKMSOpenBaoAvailability checks if OpenBao KMS is available for testing
  120. // This test can be run separately to verify the KMS setup
  121. func TestSSEKMSOpenBaoAvailability(t *testing.T) {
  122. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  123. defer cancel()
  124. client, err := createS3Client(ctx, defaultConfig)
  125. require.NoError(t, err, "Failed to create S3 client")
  126. bucketName, err := createTestBucket(ctx, client, defaultConfig.BucketPrefix+"sse-kms-availability-")
  127. require.NoError(t, err, "Failed to create test bucket")
  128. defer cleanupTestBucket(ctx, client, bucketName)
  129. // Try a simple KMS operation to verify availability
  130. testData := []byte("KMS availability test")
  131. objectKey := "kms-availability-test"
  132. kmsKeyID := "test-key-123"
  133. // This should succeed if KMS is properly configured
  134. _, err = client.PutObject(ctx, &s3.PutObjectInput{
  135. Bucket: aws.String(bucketName),
  136. Key: aws.String(objectKey),
  137. Body: bytes.NewReader(testData),
  138. ServerSideEncryption: types.ServerSideEncryptionAwsKms,
  139. SSEKMSKeyId: aws.String(kmsKeyID),
  140. })
  141. if err != nil {
  142. t.Skipf("OpenBao KMS not available for testing: %v", err)
  143. }
  144. t.Logf("✅ OpenBao KMS is available and working")
  145. // Verify we can retrieve the object
  146. getResp, err := client.GetObject(ctx, &s3.GetObjectInput{
  147. Bucket: aws.String(bucketName),
  148. Key: aws.String(objectKey),
  149. })
  150. require.NoError(t, err, "Failed to retrieve KMS test object")
  151. defer getResp.Body.Close()
  152. assert.Equal(t, types.ServerSideEncryptionAwsKms, getResp.ServerSideEncryption)
  153. t.Logf("✅ KMS encryption/decryption working correctly")
  154. }