github.com/opentofu/opentofu@v1.7.1/internal/encryption/keyprovider/aws_kms/config_test.go (about)

     1  package aws_kms
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go-v2/aws"
    10  	"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
    11  	"github.com/aws/aws-sdk-go-v2/service/kms/types"
    12  	"github.com/davecgh/go-spew/spew"
    13  	awsbase "github.com/hashicorp/aws-sdk-go-base/v2"
    14  	"github.com/hashicorp/hcl/v2"
    15  	"github.com/hashicorp/hcl/v2/hclsyntax"
    16  	"github.com/opentofu/opentofu/internal/gohcl"
    17  	"github.com/opentofu/opentofu/internal/httpclient"
    18  	"github.com/opentofu/opentofu/version"
    19  )
    20  
    21  func TestConfig_asAWSBase(t *testing.T) {
    22  	testCases := []struct {
    23  		name     string
    24  		input    string
    25  		expected awsbase.Config
    26  	}{
    27  		{
    28  			name: "minconfig",
    29  			input: `
    30  				kms_key_id = "my-kms-key-id"
    31  				key_spec = "AES_256"
    32  				region = "magic-mountain"`,
    33  			expected: awsbase.Config{
    34  				Region:                 "magic-mountain",
    35  				CallerDocumentationURL: "https://opentofu.org/docs/language/settings/backends/s3",
    36  				CallerName:             "KMS Key Provider",
    37  				MaxRetries:             5,
    38  				UserAgent: awsbase.UserAgentProducts{
    39  					{Name: "APN", Version: "1.0"},
    40  					{Name: httpclient.DefaultApplicationName, Version: version.String()},
    41  				},
    42  			},
    43  		},
    44  		{
    45  			name: "maxconfig",
    46  			input: `
    47  				kms_key_id = "my-kms-key-id"
    48  				key_spec = "AES_256"
    49  
    50  				access_key = "my-access-key"
    51  				endpoints {
    52  					iam = "endpoint-iam"
    53  					sts = "endpoint-sts"
    54  				}
    55  				max_retries = 42
    56  				profile = "my-profile"
    57  				region = "my-region"
    58  				secret_key = "my-secret-key"
    59  				skip_credentials_validation = true
    60  				skip_requesting_account_id = true
    61  				sts_region = "my-sts-region"
    62  				token = "my-token"
    63  				http_proxy = "my-http-proxy"
    64  				https_proxy = "my-https-proxy"
    65  				no_proxy = "my-noproxy"
    66  				insecure = true
    67  				use_dualstack_endpoint = true
    68  				use_fips_endpoint = true
    69  				custom_ca_bundle = "my-custom-ca-bundle"
    70  				ec2_metadata_service_endpoint = "my-emde"
    71  				ec2_metadata_service_endpoint_mode = "my-emde-mode"
    72  				skip_metadata_api_check = false
    73  				shared_credentials_files = ["my-scredf"]
    74  				shared_config_files = ["my-sconff"]
    75  				assume_role = {
    76  					role_arn = "ar_arn"
    77  					duration = "4h"
    78  					external_id = "ar_extid"
    79  					policy = "ar_policy"
    80  					policy_arns = ["arn:aws:iam::123456789012:policy/AR"]
    81  					session_name = "ar_session_name"
    82  					tags = {
    83  						foo = "bar"
    84  					}
    85  					transitive_tag_keys = ["ar_tags"]
    86  				}
    87  				assume_role_with_web_identity = {
    88  					role_arn = "wi_arn"
    89  					duration = "5h"
    90  					policy = "wi_policy"
    91  					policy_arns = ["arn:aws:iam::123456789012:policy/WI"]
    92  					session_name = "wi_session_name"
    93  					web_identity_token = "wi_token"
    94  					//web_identity_token_file = "wi_token_file"
    95  				}
    96  				allowed_account_ids = ["account"]
    97  				//forbidden_account_ids = ?
    98  				retry_mode = "adaptive"
    99  				`,
   100  			expected: awsbase.Config{
   101  				CallerDocumentationURL: "https://opentofu.org/docs/language/settings/backends/s3",
   102  				CallerName:             "KMS Key Provider",
   103  				UserAgent: awsbase.UserAgentProducts{
   104  					{Name: "APN", Version: "1.0"},
   105  					{Name: httpclient.DefaultApplicationName, Version: version.String()},
   106  				},
   107  
   108  				AccessKey:                      "my-access-key",
   109  				IamEndpoint:                    "https://endpoint-iam",
   110  				MaxRetries:                     42,
   111  				Profile:                        "my-profile",
   112  				Region:                         "my-region",
   113  				SecretKey:                      "my-secret-key",
   114  				SkipCredsValidation:            true,
   115  				SkipRequestingAccountId:        true,
   116  				StsEndpoint:                    "https://endpoint-sts",
   117  				StsRegion:                      "my-sts-region",
   118  				Token:                          "my-token",
   119  				HTTPProxy:                      aws.String("my-http-proxy"),
   120  				HTTPSProxy:                     aws.String("my-https-proxy"),
   121  				NoProxy:                        "my-noproxy",
   122  				Insecure:                       true,
   123  				UseDualStackEndpoint:           true,
   124  				UseFIPSEndpoint:                true,
   125  				CustomCABundle:                 "my-custom-ca-bundle",
   126  				EC2MetadataServiceEnableState:  imds.ClientDisabled,
   127  				EC2MetadataServiceEndpoint:     "my-emde",
   128  				EC2MetadataServiceEndpointMode: "my-emde-mode",
   129  				SharedCredentialsFiles:         []string{"my-scredf"},
   130  				SharedConfigFiles:              []string{"my-sconff"},
   131  				AssumeRole: &awsbase.AssumeRole{
   132  					RoleARN:    "ar_arn",
   133  					Duration:   time.Hour * 4,
   134  					ExternalID: "ar_extid",
   135  					Policy:     "ar_policy",
   136  					PolicyARNs: []string{
   137  						"arn:aws:iam::123456789012:policy/AR",
   138  					},
   139  					SessionName: "ar_session_name",
   140  					Tags: map[string]string{
   141  						"foo": "bar",
   142  					},
   143  					TransitiveTagKeys: []string{
   144  						"ar_tags",
   145  					},
   146  				},
   147  				AssumeRoleWithWebIdentity: &awsbase.AssumeRoleWithWebIdentity{
   148  					RoleARN:  "wi_arn",
   149  					Duration: time.Hour * 5,
   150  					Policy:   "wi_policy",
   151  					PolicyARNs: []string{
   152  						"arn:aws:iam::123456789012:policy/WI",
   153  					},
   154  					SessionName:          "wi_session_name",
   155  					WebIdentityToken:     "wi_token",
   156  					WebIdentityTokenFile: "",
   157  				},
   158  				AllowedAccountIds: []string{"account"},
   159  				RetryMode:         aws.RetryModeAdaptive,
   160  			},
   161  		},
   162  	}
   163  
   164  	for _, tc := range testCases {
   165  		t.Run(tc.name, func(t *testing.T) {
   166  			input, diags := hclsyntax.ParseConfig([]byte(tc.input), "test", hcl.InitialPos)
   167  			if diags.HasErrors() {
   168  				t.Fatal(diags.Error())
   169  			}
   170  
   171  			config := new(Config)
   172  
   173  			diags = gohcl.DecodeBody(input.Body, nil, config)
   174  			if diags.HasErrors() {
   175  				t.Fatal(diags.Error())
   176  			}
   177  
   178  			if config.KMSKeyID != "my-kms-key-id" {
   179  				t.Fatal("missing kms_key_id")
   180  			}
   181  			if config.KeySpec != "AES_256" {
   182  				t.Fatal("missing key_spec")
   183  			}
   184  
   185  			actual, err := config.asAWSBase()
   186  			if err != nil {
   187  				t.Fatal(err.Error())
   188  			}
   189  			if !reflect.DeepEqual(tc.expected, *actual) {
   190  				t.Fatalf("Expected %s, got %s", spew.Sdump(tc.expected), spew.Sdump(*actual))
   191  			}
   192  		})
   193  	}
   194  }
   195  
   196  func TestValidate(t *testing.T) {
   197  	testCases := []struct {
   198  		name     string
   199  		input    Config
   200  		expected error
   201  	}{
   202  		{
   203  			name: "valid",
   204  			input: Config{
   205  				KMSKeyID: "my-kms-key-id",
   206  				KeySpec:  "AES_256",
   207  			},
   208  			expected: nil,
   209  		},
   210  		{
   211  			name: "missing kms_key_id",
   212  			input: Config{
   213  				KMSKeyID: "",
   214  				KeySpec:  "AES_256",
   215  			},
   216  			expected: fmt.Errorf("no kms_key_id provided"),
   217  		},
   218  		{
   219  			name: "missing key_spec",
   220  			input: Config{
   221  				KMSKeyID: "my-kms-key-id",
   222  				KeySpec:  "",
   223  			},
   224  			expected: fmt.Errorf("no key_spec provided"),
   225  		},
   226  		{
   227  			name: "invalid key_spec",
   228  			input: Config{
   229  				KMSKeyID: "my-kms-key-id",
   230  				KeySpec:  "invalid??",
   231  			},
   232  		},
   233  	}
   234  
   235  	for _, tc := range testCases {
   236  		t.Run(tc.name, func(t *testing.T) {
   237  			err := tc.input.validate()
   238  			// check if the error message is the same
   239  			if tc.expected != nil {
   240  				if err.Error() != tc.expected.Error() {
   241  					t.Fatalf("Expected %q, got %q", tc.expected.Error(), err.Error())
   242  				}
   243  			}
   244  		})
   245  	}
   246  }
   247  
   248  func TestGetKeySpecAsAWSType(t *testing.T) {
   249  
   250  	aes256 := types.DataKeySpecAes256
   251  	aes128 := types.DataKeySpecAes128
   252  
   253  	cases := []struct {
   254  		key      string
   255  		expected *types.DataKeySpec
   256  	}{
   257  		{
   258  			key:      "AES_256",
   259  			expected: &aes256,
   260  		},
   261  		{
   262  			key:      "AES_128",
   263  			expected: &aes128,
   264  		},
   265  		{
   266  			key:      "",
   267  			expected: nil,
   268  		},
   269  		{
   270  			key:      "invalidKey",
   271  			expected: nil,
   272  		},
   273  	}
   274  
   275  	for _, c := range cases {
   276  		t.Run(c.key, func(t *testing.T) {
   277  			config := Config{
   278  				KeySpec: c.key,
   279  			}
   280  			actual := config.getKeySpecAsAWSType()
   281  			if !reflect.DeepEqual(c.expected, actual) {
   282  				t.Fatalf("Expected %s, got %s", spew.Sdump(c.expected), spew.Sdump(actual))
   283  			}
   284  		})
   285  	}
   286  }