or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdpolicies-tags.mdreplication.mdrotation.mdsecret-management.mdutilities.md

rotation.mddocs/

0

# Rotation Management

1

2

Automated secret rotation capabilities for seamless credential updates without service interruption. AWS Secrets Manager supports automatic rotation using AWS Lambda functions to update credentials in both the service and the secret.

3

4

## Rotation Concepts

5

6

- **AWSCURRENT**: The current active version of the secret

7

- **AWSPENDING**: The new version being created during rotation

8

- **Rotation Lambda**: AWS Lambda function that performs the actual credential rotation

9

- **Rotation Rules**: Configuration specifying when rotation should occur

10

11

## Core Rotation Operations

12

13

### Starting Rotation

14

15

#### RotateSecretRequest

16

17

```java { .api }

18

class RotateSecretRequest extends AmazonWebServiceRequest {

19

String secretId; // Required: Secret identifier

20

String clientRequestToken; // Idempotency token

21

String rotationLambdaARN; // Lambda function ARN for rotation

22

RotationRulesType rotationRules; // Rotation schedule configuration

23

Boolean rotateImmediately; // Start rotation immediately

24

Boolean forceRotateSecretVersion; // Force rotation even if AWSPENDING exists

25

}

26

```

27

28

#### RotateSecretResult

29

30

```java { .api }

31

class RotateSecretResult {

32

String arn; // Secret ARN

33

String name; // Secret name

34

String versionId; // Version ID of AWSPENDING version

35

}

36

```

37

38

#### RotationRulesType

39

40

```java { .api }

41

class RotationRulesType {

42

Long automaticallyAfterDays; // Number of days between rotations (1-1000)

43

}

44

```

45

46

#### Usage Example

47

48

```java { .api }

49

// Set up automatic rotation for database credentials

50

RotationRulesType rotationRules = new RotationRulesType()

51

.withAutomaticallyAfterDays(30L);

52

53

RotateSecretRequest rotateRequest = new RotateSecretRequest()

54

.withSecretId("rds/prod/masteruser")

55

.withRotationLambdaARN("arn:aws:lambda:us-west-2:123456789012:function:SecretsManagerRotation")

56

.withRotationRules(rotationRules)

57

.withRotateImmediately(true);

58

59

RotateSecretResult rotateResult = client.rotateSecret(rotateRequest);

60

System.out.println("Started rotation for secret: " + rotateResult.getName());

61

System.out.println("AWSPENDING version: " + rotateResult.getVersionId());

62

63

// Start immediate rotation without changing schedule

64

RotateSecretRequest immediateRotateRequest = new RotateSecretRequest()

65

.withSecretId("api/service/token")

66

.withRotateImmediately(true);

67

68

RotateSecretResult immediateResult = client.rotateSecret(immediateRotateRequest);

69

```

70

71

### Canceling Rotation

72

73

#### CancelRotateSecretRequest

74

75

```java { .api }

76

class CancelRotateSecretRequest extends AmazonWebServiceRequest {

77

String secretId; // Required: Secret identifier

78

}

79

```

80

81

#### CancelRotateSecretResult

82

83

```java { .api }

84

class CancelRotateSecretResult {

85

String arn; // Secret ARN

86

String name; // Secret name

87

String versionId; // Version ID of cancelled rotation

88

}

89

```

90

91

#### Usage Example

92

93

```java { .api }

94

// Cancel an in-progress rotation

95

CancelRotateSecretRequest cancelRequest = new CancelRotateSecretRequest()

96

.withSecretId("rds/prod/masteruser");

97

98

try {

99

CancelRotateSecretResult cancelResult = client.cancelRotateSecret(cancelRequest);

100

System.out.println("Cancelled rotation for: " + cancelResult.getName());

101

} catch (InvalidRequestException e) {

102

System.err.println("No rotation in progress or cannot cancel: " + e.getMessage());

103

}

104

```

105

106

## Rotation Configuration

107

108

### Configuring Rotation During Secret Creation

109

110

```java { .api }

111

// Create secret with rotation configuration

112

RotationRulesType rotationRules = new RotationRulesType()

113

.withAutomaticallyAfterDays(45L);

114

115

CreateSecretRequest createWithRotation = new CreateSecretRequest()

116

.withName("database/credentials")

117

.withSecretString("{\"username\":\"admin\",\"password\":\"initialPassword\"}")

118

.withDescription("Database credentials with automatic rotation");

119

120

// First create the secret

121

CreateSecretResult createResult = client.createSecret(createWithRotation);

122

123

// Then configure rotation

124

RotateSecretRequest configureRotation = new RotateSecretRequest()

125

.withSecretId(createResult.getName())

126

.withRotationLambdaARN("arn:aws:lambda:us-west-2:123456789012:function:DatabaseRotation")

127

.withRotationRules(rotationRules);

128

129

RotateSecretResult rotationConfig = client.rotateSecret(configureRotation);

130

```

131

132

### Updating Rotation Configuration

133

134

```java { .api }

135

// Update rotation schedule

136

RotationRulesType newRules = new RotationRulesType()

137

.withAutomaticallyAfterDays(60L); // Change from 30 to 60 days

138

139

RotateSecretRequest updateRotation = new RotateSecretRequest()

140

.withSecretId("rds/prod/masteruser")

141

.withRotationRules(newRules);

142

143

RotateSecretResult updateResult = client.rotateSecret(updateRotation);

144

145

// Change rotation Lambda function

146

RotateSecretRequest updateLambda = new RotateSecretRequest()

147

.withSecretId("api/credentials")

148

.withRotationLambdaARN("arn:aws:lambda:us-west-2:123456789012:function:NewRotationFunction");

149

150

RotateSecretResult lambdaUpdate = client.rotateSecret(updateLambda);

151

```

152

153

## Version Stage Management

154

155

### Understanding Version Stages

156

157

- **AWSCURRENT**: The currently active secret version

158

- **AWSPENDING**: A new version being created during rotation

159

- **Custom Stages**: User-defined stages for specific use cases

160

161

### Moving Version Stages

162

163

#### UpdateSecretVersionStageRequest

164

165

```java { .api }

166

class UpdateSecretVersionStageRequest extends AmazonWebServiceRequest {

167

String secretId; // Required: Secret identifier

168

String versionStage; // Required: Stage to move

169

String clientRequestToken; // Idempotency token

170

String moveToVersionId; // Version to move stage to

171

String removeFromVersionId; // Version to remove stage from

172

}

173

```

174

175

#### UpdateSecretVersionStageResult

176

177

```java { .api }

178

class UpdateSecretVersionStageResult {

179

String arn; // Secret ARN

180

String name; // Secret name

181

}

182

```

183

184

#### Usage Example

185

186

```java { .api }

187

// Promote AWSPENDING to AWSCURRENT (complete rotation)

188

UpdateSecretVersionStageRequest promoteRequest = new UpdateSecretVersionStageRequest()

189

.withSecretId("rds/prod/masteruser")

190

.withVersionStage("AWSCURRENT")

191

.withMoveToVersionId("new-version-id")

192

.withRemoveFromVersionId("old-version-id");

193

194

UpdateSecretVersionStageResult promoteResult = client.updateSecretVersionStage(promoteRequest);

195

196

// Create custom stage for testing

197

UpdateSecretVersionStageRequest testStageRequest = new UpdateSecretVersionStageRequest()

198

.withSecretId("api/credentials")

199

.withVersionStage("TESTING")

200

.withMoveToVersionId("test-version-id");

201

202

UpdateSecretVersionStageResult testResult = client.updateSecretVersionStage(testStageRequest);

203

204

// Rollback by moving AWSCURRENT to previous version

205

UpdateSecretVersionStageRequest rollbackRequest = new UpdateSecretVersionStageRequest()

206

.withSecretId("database/password")

207

.withVersionStage("AWSCURRENT")

208

.withMoveToVersionId("previous-version-id")

209

.withRemoveFromVersionId("current-version-id");

210

211

UpdateSecretVersionStageResult rollbackResult = client.updateSecretVersionStage(rollbackRequest);

212

```

213

214

## Rotation Monitoring

215

216

### Checking Rotation Status

217

218

```java { .api }

219

// Check rotation status using describe

220

DescribeSecretRequest statusRequest = new DescribeSecretRequest()

221

.withSecretId("rds/prod/masteruser");

222

223

DescribeSecretResult statusResult = client.describeSecret(statusRequest);

224

225

System.out.println("Rotation Enabled: " + statusResult.getRotationEnabled());

226

System.out.println("Rotation Lambda: " + statusResult.getRotationLambdaARN());

227

System.out.println("Last Rotated: " + statusResult.getLastRotatedDate());

228

System.out.println("Next Rotation: " + statusResult.getNextRotationDate());

229

230

if (statusResult.getRotationRules() != null) {

231

Long days = statusResult.getRotationRules().getAutomaticallyAfterDays();

232

System.out.println("Rotation Interval: " + days + " days");

233

}

234

235

// Check version stages to see rotation progress

236

Map<String, List<String>> versionStages = statusResult.getVersionIdsToStages();

237

for (Map.Entry<String, List<String>> entry : versionStages.entrySet()) {

238

String versionId = entry.getKey();

239

List<String> stages = entry.getValue();

240

241

if (stages.contains("AWSPENDING")) {

242

System.out.println("Rotation in progress - AWSPENDING version: " + versionId);

243

}

244

if (stages.contains("AWSCURRENT")) {

245

System.out.println("Current active version: " + versionId);

246

}

247

}

248

```

249

250

### Handling Rotation States

251

252

```java { .api }

253

public class RotationStatusChecker {

254

255

public enum RotationState {

256

NOT_CONFIGURED,

257

CONFIGURED_NOT_ROTATING,

258

ROTATION_IN_PROGRESS,

259

ROTATION_FAILED

260

}

261

262

public RotationState checkRotationState(AWSSecretsManager client, String secretId) {

263

try {

264

DescribeSecretResult result = client.describeSecret(

265

new DescribeSecretRequest().withSecretId(secretId));

266

267

// Check if rotation is configured

268

if (!Boolean.TRUE.equals(result.getRotationEnabled())) {

269

return RotationState.NOT_CONFIGURED;

270

}

271

272

// Check for AWSPENDING version

273

Map<String, List<String>> versions = result.getVersionIdsToStages();

274

boolean hasPending = versions.values().stream()

275

.anyMatch(stages -> stages.contains("AWSPENDING"));

276

277

if (hasPending) {

278

// Check if rotation is stuck (older than expected)

279

Date lastRotated = result.getLastRotatedDate();

280

long hoursSinceRotation = (System.currentTimeMillis() -

281

lastRotated.getTime()) / (1000 * 60 * 60);

282

283

if (hoursSinceRotation > 24) { // Rotation taking too long

284

return RotationState.ROTATION_FAILED;

285

}

286

return RotationState.ROTATION_IN_PROGRESS;

287

}

288

289

return RotationState.CONFIGURED_NOT_ROTATING;

290

291

} catch (Exception e) {

292

System.err.println("Error checking rotation state: " + e.getMessage());

293

return RotationState.ROTATION_FAILED;

294

}

295

}

296

}

297

```

298

299

## Advanced Rotation Scenarios

300

301

### Database Credential Rotation

302

303

```java { .api }

304

// Rotate RDS database master password

305

public void rotateRDSMasterPassword(String secretId, String dbInstanceId) {

306

// The rotation Lambda function will:

307

// 1. Create new password in AWSPENDING version

308

// 2. Update RDS master password

309

// 3. Test new credentials

310

// 4. Move AWSCURRENT stage to new version

311

312

RotateSecretRequest rotateRequest = new RotateSecretRequest()

313

.withSecretId(secretId)

314

.withRotationLambdaARN("arn:aws:lambda:region:account:function:SecretsManagerRDSMySQLRotationSingleUser")

315

.withRotateImmediately(true);

316

317

try {

318

RotateSecretResult result = client.rotateSecret(rotateRequest);

319

System.out.println("Started RDS rotation: " + result.getVersionId());

320

321

// Wait for rotation to complete

322

waitForRotationCompletion(secretId);

323

324

} catch (Exception e) {

325

System.err.println("Rotation failed: " + e.getMessage());

326

}

327

}

328

329

private void waitForRotationCompletion(String secretId) {

330

int maxWaitMinutes = 15;

331

int waitIntervalSeconds = 30;

332

int attempts = (maxWaitMinutes * 60) / waitIntervalSeconds;

333

334

for (int i = 0; i < attempts; i++) {

335

try {

336

DescribeSecretResult result = client.describeSecret(

337

new DescribeSecretRequest().withSecretId(secretId));

338

339

Map<String, List<String>> versions = result.getVersionIdsToStages();

340

boolean hasPending = versions.values().stream()

341

.anyMatch(stages -> stages.contains("AWSPENDING"));

342

343

if (!hasPending) {

344

System.out.println("Rotation completed successfully");

345

return;

346

}

347

348

Thread.sleep(waitIntervalSeconds * 1000);

349

350

} catch (InterruptedException e) {

351

Thread.currentThread().interrupt();

352

break;

353

} catch (Exception e) {

354

System.err.println("Error checking rotation status: " + e.getMessage());

355

}

356

}

357

358

System.err.println("Rotation did not complete within expected time");

359

}

360

```

361

362

### Multi-User Rotation

363

364

```java { .api }

365

// Rotate credentials for multi-user scenarios (alternating users)

366

public void rotateMultiUserCredentials(String secretId) {

367

RotateSecretRequest rotateRequest = new RotateSecretRequest()

368

.withSecretId(secretId)

369

.withRotationLambdaARN("arn:aws:lambda:region:account:function:SecretsManagerRDSMySQLRotationMultiUser")

370

.withRotationRules(new RotationRulesType().withAutomaticallyAfterDays(30L))

371

.withRotateImmediately(true);

372

373

RotateSecretResult result = client.rotateSecret(rotateRequest);

374

System.out.println("Started multi-user rotation: " + result.getVersionId());

375

}

376

```

377

378

### Custom Application Rotation

379

380

```java { .api }

381

// Rotate API keys or application-specific credentials

382

public void rotateAPIKey(String secretId, String apiEndpoint) {

383

RotateSecretRequest rotateRequest = new RotateSecretRequest()

384

.withSecretId(secretId)

385

.withRotationLambdaARN("arn:aws:lambda:region:account:function:CustomAPIKeyRotation")

386

.withRotateImmediately(true);

387

388

try {

389

RotateSecretResult result = client.rotateSecret(rotateRequest);

390

System.out.println("Started API key rotation: " + result.getVersionId());

391

392

// The Lambda function should:

393

// 1. Generate new API key via the service API

394

// 2. Store new key in AWSPENDING version

395

// 3. Test new key works

396

// 4. Optionally revoke old key

397

// 5. Move AWSCURRENT stage to new version

398

399

} catch (Exception e) {

400

System.err.println("API key rotation failed: " + e.getMessage());

401

}

402

}

403

```

404

405

## Error Handling

406

407

Common rotation-related exceptions:

408

409

```java { .api }

410

try {

411

RotateSecretResult result = client.rotateSecret(rotateRequest);

412

} catch (ResourceNotFoundException e) {

413

System.err.println("Secret not found: " + e.getMessage());

414

} catch (InvalidParameterException e) {

415

System.err.println("Invalid rotation configuration: " + e.getMessage());

416

} catch (InvalidRequestException e) {

417

System.err.println("Rotation cannot be performed: " + e.getMessage());

418

} catch (LimitExceededException e) {

419

System.err.println("Too many rotation requests: " + e.getMessage());

420

} catch (PreconditionNotMetException e) {

421

System.err.println("Rotation precondition failed: " + e.getMessage());

422

} catch (AWSSecretsManagerException e) {

423

System.err.println("Rotation service error: " + e.getMessage());

424

}

425

426

// Handle rotation cancellation errors

427

try {

428

CancelRotateSecretResult result = client.cancelRotateSecret(cancelRequest);

429

} catch (InvalidRequestException e) {

430

// Common reasons:

431

// - No rotation in progress

432

// - Rotation too far along to cancel

433

// - Lambda function already executing

434

System.err.println("Cannot cancel rotation: " + e.getMessage());

435

}

436

```

437

438

## Best Practices

439

440

1. **Lambda Function Setup**: Ensure rotation Lambda has proper IAM permissions

441

2. **Testing**: Test rotation in non-production environments first

442

3. **Monitoring**: Set up CloudWatch alarms for rotation failures

443

4. **Rollback Plan**: Know how to rollback using version stage management

444

5. **Network Access**: Ensure Lambda can reach both Secrets Manager and target service

445

6. **Error Handling**: Implement proper retry logic for transient failures

446

7. **Scheduling**: Choose rotation intervals based on security requirements

447

8. **Multi-Region**: Consider cross-region implications for replicated secrets