Manage AWS Secrets Manager Secret Versions

The aws:secretsmanager/secretVersion:SecretVersion resource, part of the Pulumi AWS provider, manages the actual secret value and version within an existing Secrets Manager secret container. This guide focuses on two capabilities: storing string and JSON secret values, and parsing structured secrets for application use.

Secret versions belong to an aws.secretsmanager.Secret resource, which provides the container and metadata. The examples are intentionally small. Combine them with your own secret containers and rotation policies.

Store a simple string secret value

Most secret storage begins with a single credential like an API key or password.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.secretsmanager.SecretVersion("example", {
    secretId: exampleAwsSecretsmanagerSecret.id,
    secretString: "example-string-to-protect",
});
import pulumi
import pulumi_aws as aws

example = aws.secretsmanager.SecretVersion("example",
    secret_id=example_aws_secretsmanager_secret["id"],
    secret_string="example-string-to-protect")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/secretsmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := secretsmanager.NewSecretVersion(ctx, "example", &secretsmanager.SecretVersionArgs{
			SecretId:     pulumi.Any(exampleAwsSecretsmanagerSecret.Id),
			SecretString: pulumi.String("example-string-to-protect"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.SecretsManager.SecretVersion("example", new()
    {
        SecretId = exampleAwsSecretsmanagerSecret.Id,
        SecretString = "example-string-to-protect",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.secretsmanager.SecretVersion;
import com.pulumi.aws.secretsmanager.SecretVersionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new SecretVersion("example", SecretVersionArgs.builder()
            .secretId(exampleAwsSecretsmanagerSecret.id())
            .secretString("example-string-to-protect")
            .build());

    }
}
resources:
  example:
    type: aws:secretsmanager:SecretVersion
    properties:
      secretId: ${exampleAwsSecretsmanagerSecret.id}
      secretString: example-string-to-protect

The secretId property references the secret container where this version will be stored. The secretString property holds the actual credential value. Secrets Manager encrypts the value at rest and manages access through IAM policies.

Store structured configuration as JSON

Applications often need multiple related credentials grouped together. Secrets Manager accepts JSON for structured data.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();
const example = config.getObject<Record<string, string>>("example") || {
    key1: "value1",
    key2: "value2",
};
const exampleSecretVersion = new aws.secretsmanager.SecretVersion("example", {
    secretId: exampleAwsSecretsmanagerSecret.id,
    secretString: JSON.stringify(example),
});
import pulumi
import json
import pulumi_aws as aws

config = pulumi.Config()
example = config.get_object("example")
if example is None:
    example = {
        "key1": "value1",
        "key2": "value2",
    }
example_secret_version = aws.secretsmanager.SecretVersion("example",
    secret_id=example_aws_secretsmanager_secret["id"],
    secret_string=json.dumps(example))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/secretsmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		cfg := config.New(ctx, "")
		example := map[string]interface{}{
			"key1": "value1",
			"key2": "value2",
		}
		if param := cfg.GetObject("example"); param != nil {
			example = param
		}
		tmpJSON0, err := json.Marshal(example)
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = secretsmanager.NewSecretVersion(ctx, "example", &secretsmanager.SecretVersionArgs{
			SecretId:     pulumi.Any(exampleAwsSecretsmanagerSecret.Id),
			SecretString: pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var config = new Config();
    var example = config.GetObject<Dictionary<string, string>>("example") ?? 
    {
        { "key1", "value1" },
        { "key2", "value2" },
    };
    var exampleSecretVersion = new Aws.SecretsManager.SecretVersion("example", new()
    {
        SecretId = exampleAwsSecretsmanagerSecret.Id,
        SecretString = JsonSerializer.Serialize(example),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.secretsmanager.SecretVersion;
import com.pulumi.aws.secretsmanager.SecretVersionArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var config = ctx.config();
        final var example = config.get("example").orElse(Map.ofEntries(
            Map.entry("key1", "value1"),
            Map.entry("key2", "value2")
        ));
        var exampleSecretVersion = new SecretVersion("exampleSecretVersion", SecretVersionArgs.builder()
            .secretId(exampleAwsSecretsmanagerSecret.id())
            .secretString(serializeJson(
                example))
            .build());

    }
}
configuration:
  # The map here can come from other supported configurations
  # like locals, resource attribute, map() built-in, etc.
  example:
    type: map(string)
    default:
      key1: value1
      key2: value2
resources:
  exampleSecretVersion:
    type: aws:secretsmanager:SecretVersion
    name: example
    properties:
      secretId: ${exampleAwsSecretsmanagerSecret.id}
      secretString:
        fn::toJSON: ${example}

JSON.stringify converts the key-value pairs into a string that Secrets Manager can store. This allows you to group related credentials (database username and password, API keys and endpoints) in a single secret rather than managing multiple separate secrets.

Read JSON secrets back into application code

After storing structured secrets, applications parse them back into native data structures.

import * as pulumi from "@pulumi/pulumi";
import * as std from "@pulumi/std";

export const example = std.jsondecode({
    input: exampleAwsSecretsmanagerSecretVersion.secretString,
}).then(invoke => invoke.result?.key1);
import pulumi
import pulumi_std as std

pulumi.export("example", std.jsondecode(input=example_aws_secretsmanager_secret_version["secretString"]).result["key1"])
package main

import (
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		ctx.Export("example", pulumi.Any(std.Jsondecode(ctx, &std.JsondecodeArgs{
			Input: exampleAwsSecretsmanagerSecretVersion.SecretString,
		}, nil).Result.Key1))
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    return new Dictionary<string, object?>
    {
        ["example"] = Std.Jsondecode.Invoke(new()
        {
            Input = exampleAwsSecretsmanagerSecretVersion.SecretString,
        }).Apply(invoke => invoke.Result?.Key1),
    };
});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.JsondecodeArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        ctx.export("example", StdFunctions.jsondecode(JsondecodeArgs.builder()
            .input(exampleAwsSecretsmanagerSecretVersion.secretString())
            .build()).result().key1());
    }
}
outputs:
  example:
    fn::invoke:
      function: std:jsondecode
      arguments:
        input: ${exampleAwsSecretsmanagerSecretVersion.secretString}
      return: result.key1

The jsondecode function parses the secretString back into a map, allowing you to access individual keys. This example retrieves the key1 value from the JSON structure stored in the previous example.

Beyond these examples

These snippets focus on specific secret version features: string and JSON secret storage, and secret value parsing and retrieval. They’re intentionally minimal rather than full secret management solutions.

The examples require pre-existing infrastructure such as the aws.secretsmanager.Secret resource (the secret container itself). They focus on storing and retrieving secret values rather than provisioning the secret metadata.

To keep things focused, common secret version patterns are omitted, including:

  • Version staging labels (versionStages)
  • Binary secret data (secretBinary)
  • Write-only secret updates (secretStringWo, secretStringWoVersion)
  • Secret rotation and lifecycle management

These omissions are intentional: the goal is to illustrate how secret values are stored and retrieved, not provide drop-in secret management modules. See the SecretVersion resource reference for all available configuration options.

Let's manage AWS Secrets Manager Secret Versions

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Version Lifecycle & Staging Labels
Why is my secret version still active after deleting the resource?
If the AWSCURRENT staging label is present during deletion, it can’t be removed and the version stays active. Move the AWSCURRENT label to another version before or after deleting the resource to fully deprecate this version.
Why am I seeing a perpetual difference with versionStages?
If you configure versionStages, you must include the AWSCURRENT staging label when this is the only version or when the label is currently present on this version. Otherwise, Pulumi will show a perpetual difference.
Secret Value Configuration
What's the difference between secretString, secretBinary, and secretStringWo?

These are mutually exclusive options for storing secret data:

  • secretString: Standard text data (use for most cases)
  • secretBinary: Binary data encoded as base64
  • secretStringWo: Write-only text data that doesn’t update in state (use when you don’t want the value stored in state)
How do I store JSON key-value pairs in a secret?
Use JSON.stringify() to convert your object to a string for secretString, as shown in the key-value pairs example.
How do I read JSON values back from a secret?
Use std.jsondecode() to parse the secretString back into a native object, then access individual keys.
Write-Only Secrets
Why doesn't secretStringWo show updated values in state?
The secretStringWo field is write-only and its value is not updated in state during read operations. This is by design to avoid storing sensitive values in state.
How do I update a secret using secretStringWo?
Increment the secretStringWoVersion integer whenever you update secretStringWo. This triggers Pulumi to recognize the change and update the secret.
Immutability & Updates
What properties can't be changed after creation?
The following properties are immutable: secretId, secretBinary, secretString, and secretStringWoVersion. Changing these requires creating a new secret version.

Using a different cloud?

Explore security guides for other cloud providers: