List deleted secrets from AWS Secrets Manager
Tags: aws, security, secretsmanager
Published: 2022-11-23 17:15:24


The secret manager is sooo good at hiding things that the API or AWS CLI does not show you secrets scheduled for deletion... But you can cheat your way around this. The GOpher can discover the secret...



Update March 2023:

AWS Secrets Manager now supports listing secrets scheduled for deletion with a new request parameter, IncludePlannedDeletion.

Thanks to Simon Marty for pointing it out and updating my code!

---

When you delete a secret from *AWS Secrets Manager*, the standard 

```bash
aws secretsmanager list-secrets
```

does *not* show these secrets.

Also, there is _no_ parameter to show the deleted /schedules for deletion secrets.

In the AWS console, you have the option to show these secrets also:

![Preferences](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8ax0mc8ol8uwmymrpri.png)

Debugging the AWS console, you see that the console is cheating and using a parameter not defined in the API
Definition, see [APIdoc](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_ListSecrets.html#API_ListSecrets_RequestParameters).


![Debug the console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vxhv38kvz2zdrenz1m86.png)

So you have to change the content of the request to:

```json
{
  "MaxResults": 100,
  "IncludeDeleted": true,
  "SortOrder": "desc",
  "Filters": []
}
```

## Implement with GO SDK V2

In go the input parameter for the `secretsmanager.ListSecrets` are well-defined, so any attempt to add a field will go wrong.

But because of the GO middleware, you can manipulate requests at all stages.

See [AWS GO SDK V2 Middleware](https://aws.github.io/aws-sdk-go-v2/docs/middleware/) for documentation.

The middleware has several steps:


Stack Step |	Description
---|---
Initialize	|Prepares the input and sets any default parameters as needed.
Serialize	|Serializes the input to a protocol format suitable for the target transport layer.
Build	|Attach additional metadata to the serialised input, such as HTTP Content-Length.
Finalize |	Final message preparation, including retries and authentication (SigV4 signing).
Deserialize |	Deserialize responses from the protocol format into a structured type or error.

The *Build* step seems fine for this.

So we append a function to the cfg with `ApiOptions`:

````go
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    panic("configuration error, " + err.Error())
}

cfg.APIOptions = append(cf.APIOptions, func(stack *middleware. Stack) error {
    // Attach the custom middleware to the beginning of the Build step
    return stack.Build.Add(secret parameter, middleware.Before)
})
client = secretsmanager.NewFromConfig(cfg)
```

The function `secretsmanager` now replaces the JSON content of the request to the API with the JSON data, which the console uses.

## Run

Create a secret "deleteme" in the AWS console and delete it again. The AWS CLI will show you an empty list:

```bash
aws secretsmanager list-secrets
{
    "SecretList": []
}
```

With this[this](https://github.com/megaproaktiv/listdeletedsecrets) programm:

```bash
go run main.go
```

You get the Output:

```bash
Results
=======
Secret: deleteme / deleted on 2022-11-23 12:23:58.374 +0000 UTC
```

## Show details

Now you may describe the secret:

```bash
aws secretsmanager describe-secret --secret-id deleteme
```

## Really delete

And you can delete it for good - use it at your own risk!

```bash
aws secretsmanager delete-secret --secret-id deleteme --force-delete-without-recovery
```


## Source

See [github](https://github.com/megaproaktiv/listdeletedsecrets) for the source code and the releases to download an executable : [Release](https://github.com/megaproaktiv/listdeletedsecrets/releases/tag/v0.1.1)