Search code examples
amazon-web-servicestestcontainerslocalstacksecret-manager

Localstack throws The security token included in the request is invalid


I use Localstack with Testcontainers((testcontainers:localstack:1.15.2 )) for integration tests and set up the secret in the test setup like this: Code sample

 import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.CreateSecretRequest; 
import org.junit.Rule;
import org.junit.Test;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.utility.DockerImageName; 
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SECRETSMANAGER;

public class QueueServiceTest {

    DockerImageName localstackImage = DockerImageName.parse("localstack/localstack:0.11.3");
    @Rule
    public LocalStackContainer localstack = new LocalStackContainer(localstackImage)
            .withServices(SECRETSMANAGER).withEnv("LOCALSTACK_HOSTNAME", "localhost").withEnv("HOSTNAME", "localhost");
    @Test
    public void someTestMethod() {
        AWSSecretsManager secretsManager = AWSSecretsManagerClientBuilder.standard()
                .withCredentials(localstack.getDefaultCredentialsProvider()).withRegion(localstack.getRegion())
                .build();

        String secretString = "usrnme";
        CreateSecretRequest request = new CreateSecretRequest().withName("test")
                .withSecretString(secretString)
     .withRequestCredentialsProvider(localstack.getDefaultCredentialsProvider());
        secretsManager.createSecret(request);
    }

}

Now the test crashes with an error:

com.amazonaws.services.secretsmanager.model.AWSSecretsManagerException: The security token included in the request is invalid. (Service: AWSSecretsManager; Status Code: 400; Error Code: UnrecognizedClientException; Request ID: 314b0dee-69ed-4b08-9cd0-2618b8e14b25; Proxy: null)

at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1819) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleServiceErrorResponse(AmazonHttpClient.java:1403) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1372) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1145) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744) at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704) at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686) at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550) at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530) at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.doInvoke(AWSSecretsManagerClient.java:2625) at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.invoke(AWSSecretsManagerClient.java:2594) at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.invoke(AWSSecretsManagerClient.java:2583) at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.executeCreateSecret(AWSSecretsManagerClient.java:557) at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.createSecret(AWSSecretsManagerClient.java:528)

I think I am missing some parameters, could anyone please helo me figure it out.


Solution

  • The endpoint configuration for the AWSSecretsManagerClientBuilder is missing. Right now your client targets the real AWS endpoint, e.g.: https://secretsmanager.us-east-1.amazonaws.com:443

    public class LocalStackSecretsManagerTest {
    
      DockerImageName localstackImage = DockerImageName.parse("localstack/localstack:0.11.3");
    
      @Rule
      public LocalStackContainer localstack = new LocalStackContainer(localstackImage)
        .withServices(SECRETSMANAGER)
        .withEnv("LOCALSTACK_HOSTNAME", "localhost")
        .withEnv("HOSTNAME", "localhost");
    
      @Test
       void someTestMethod() {
        AWSSecretsManager secretsManager = AWSSecretsManagerClientBuilder.standard()
          .withCredentials(localstack.getDefaultCredentialsProvider())
          .withEndpointConfiguration(localstack.getEndpointConfiguration(SECRETSMANAGER)) // this is the important line
          .build();
    
        String secretString = "usrnme";
    
        CreateSecretRequest request = new CreateSecretRequest()
          .withName("test")
          .withSecretString(secretString);
    
        secretsManager.createSecret(request);
      }
    }
    

    When specifying the endpoint, you can remove the region configuration.

    The additional .withRequestCredentialsProvider(localstack.getDefaultCredentialsProvider()); on CreateSecretRequest is redundant and only required if you want to override the credentials provider per CreateSecretRequest .