Utility operations for decoding authorization messages and retrieving access key information. These operations are essential for debugging access denied errors, troubleshooting permissions, and key management.
Decodes authorization failure messages returned by AWS services when access is denied. This operation helps developers understand why their requests were denied.
/**
* Command for decoding authorization failure messages
* Decodes the authorization status information returned by AWS services
*/
class DecodeAuthorizationMessageCommand {
constructor(input: DecodeAuthorizationMessageCommandInput);
}
/**
* Input parameters for DecodeAuthorizationMessage operation
*/
interface DecodeAuthorizationMessageCommandInput extends DecodeAuthorizationMessageRequest {
/** The encoded authorization failure message (required) */
EncodedMessage: string;
}
/**
* Output from DecodeAuthorizationMessage operation
*/
interface DecodeAuthorizationMessageCommandOutput extends DecodeAuthorizationMessageResponse, MetadataBearer {
/** The decoded authorization failure message */
DecodedMessage?: string;
}Usage Examples:
import { STSClient, DecodeAuthorizationMessageCommand } from "@aws-sdk/client-sts";
const client = new STSClient({ region: "us-east-1" });
// Decode an authorization message from an AWS service error
const encodedMessage = "VGhpcyBpcyBhbiBlbmNvZGVkIG1lc3NhZ2U..."; // From AWS error response
const command = new DecodeAuthorizationMessageCommand({
EncodedMessage: encodedMessage
});
try {
const response = await client.send(command);
const decodedMessage = JSON.parse(response.DecodedMessage || "{}");
console.log("Decoded authorization message:");
console.log("Action:", decodedMessage.action);
console.log("Resource:", decodedMessage.resource);
console.log("Principal:", decodedMessage.principal);
console.log("Policy:", decodedMessage.policy);
console.log("Context:", decodedMessage.context);
} catch (error) {
console.error("Failed to decode message:", error);
}
// Helper function for handling AWS SDK errors with encoded messages
const handleAwsError = async (error: any) => {
if (error.code === 'UnauthorizedOperation' && error.EncodedAuthorizationFailureMessage) {
try {
const command = new DecodeAuthorizationMessageCommand({
EncodedMessage: error.EncodedAuthorizationFailureMessage
});
const response = await client.send(command);
const decoded = JSON.parse(response.DecodedMessage || "{}");
console.log("Authorization failure details:");
console.log("- Action attempted:", decoded.action);
console.log("- Resource:", decoded.resource);
console.log("- Reason:", decoded.allowed === false ? "Access denied" : "Unknown");
return decoded;
} catch (decodeError) {
console.error("Could not decode authorization message:", decodeError);
return null;
}
}
throw error;
};
// Example usage with EC2 operation that might fail
import { EC2Client, DescribeInstancesCommand } from "@aws-sdk/client-ec2";
const ec2Client = new EC2Client({ region: "us-east-1" });
try {
await ec2Client.send(new DescribeInstancesCommand({}));
} catch (error) {
const decodedInfo = await handleAwsError(error);
if (decodedInfo) {
console.log("Troubleshooting info:", decodedInfo);
}
}
// Batch decode multiple authorization messages
const decodeMessages = async (encodedMessages: string[]) => {
const results = await Promise.allSettled(
encodedMessages.map(async (encoded) => {
const command = new DecodeAuthorizationMessageCommand({
EncodedMessage: encoded
});
const response = await client.send(command);
return {
encoded,
decoded: JSON.parse(response.DecodedMessage || "{}")
};
})
);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Message ${index + 1}:`, result.value.decoded);
} else {
console.error(`Failed to decode message ${index + 1}:`, result.reason);
}
});
return results;
};Returns information about the specified access key ID, including the account ID that owns the access key. Useful for key management and verification.
/**
* Command for retrieving access key information
* Returns account information for the specified access key ID
*/
class GetAccessKeyInfoCommand {
constructor(input: GetAccessKeyInfoCommandInput);
}
/**
* Input parameters for GetAccessKeyInfo operation
*/
interface GetAccessKeyInfoCommandInput extends GetAccessKeyInfoRequest {
/** The identifier of an access key (required) */
AccessKeyId: string;
}
/**
* Output from GetAccessKeyInfo operation
*/
interface GetAccessKeyInfoCommandOutput extends GetAccessKeyInfoResponse, MetadataBearer {
/** AWS account ID that owns the access key */
Account?: string;
}Usage Examples:
import { STSClient, GetAccessKeyInfoCommand } from "@aws-sdk/client-sts";
const client = new STSClient({ region: "us-east-1" });
// Check which account owns an access key
const command = new GetAccessKeyInfoCommand({
AccessKeyId: "AKIAIOSFODNN7EXAMPLE"
});
const response = await client.send(command);
console.log(`Access key belongs to account: ${response.Account}`);
// Validate access key ownership for security
const validateAccessKey = async (accessKeyId: string, expectedAccount: string) => {
try {
const command = new GetAccessKeyInfoCommand({ AccessKeyId: accessKeyId });
const response = await client.send(command);
if (response.Account === expectedAccount) {
console.log("✓ Access key ownership validated");
return { valid: true, account: response.Account };
} else {
console.warn(`✗ Key belongs to ${response.Account}, expected ${expectedAccount}`);
return { valid: false, account: response.Account, expected: expectedAccount };
}
} catch (error) {
console.error("Failed to validate access key:", error);
return { valid: false, error: error.message };
}
};
const validation = await validateAccessKey("AKIAIOSFODNN7EXAMPLE", "123456789012");
// Access key audit function
const auditAccessKeys = async (accessKeyIds: string[]) => {
console.log(`Auditing ${accessKeyIds.length} access keys...`);
const results = await Promise.allSettled(
accessKeyIds.map(async (keyId) => {
const command = new GetAccessKeyInfoCommand({ AccessKeyId: keyId });
const response = await client.send(command);
return {
keyId,
account: response.Account,
timestamp: new Date().toISOString()
};
})
);
const successful = results
.filter((r): r is PromiseFulfilledResult<any> => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
.map(r => r.reason);
console.log(`✓ Successfully audited ${successful.length} keys`);
console.log(`✗ Failed to audit ${failed.length} keys`);
// Group by account
const byAccount = successful.reduce((acc, item) => {
const account = item.account || 'unknown';
if (!acc[account]) acc[account] = [];
acc[account].push(item.keyId);
return acc;
}, {} as Record<string, string[]>);
console.log("Keys by account:");
Object.entries(byAccount).forEach(([account, keys]) => {
console.log(` ${account}: ${keys.length} keys`);
});
return { successful, failed, byAccount };
};
// Example audit
const auditResult = await auditAccessKeys([
"AKIAIOSFODNN7EXAMPLE",
"AKIAI44QH8DHBEXAMPLE",
"AKIA266EXAMPLE"
]);
// Cross-account key detection
const detectCrossAccountKeys = async (accessKeyIds: string[], trustedAccounts: string[]) => {
const results = await Promise.allSettled(
accessKeyIds.map(async (keyId) => {
const command = new GetAccessKeyInfoCommand({ AccessKeyId: keyId });
const response = await client.send(command);
return { keyId, account: response.Account };
})
);
const crossAccountKeys = results
.filter((r): r is PromiseFulfilledResult<any> => r.status === 'fulfilled')
.map(r => r.value)
.filter(item => item.account && !trustedAccounts.includes(item.account));
if (crossAccountKeys.length > 0) {
console.warn("⚠️ Cross-account keys detected:");
crossAccountKeys.forEach(item => {
console.warn(` ${item.keyId} belongs to untrusted account: ${item.account}`);
});
} else {
console.log("✓ All keys belong to trusted accounts");
}
return crossAccountKeys;
};
const crossAccountKeys = await detectCrossAccountKeys(
["AKIAIOSFODNN7EXAMPLE", "AKIAI44QH8DHBEXAMPLE"],
["123456789012", "987654321098"] // Trusted accounts
);Helper functions for common troubleshooting scenarios:
import {
STSClient,
DecodeAuthorizationMessageCommand,
GetAccessKeyInfoCommand,
GetCallerIdentityCommand
} from "@aws-sdk/client-sts";
/**
* Comprehensive troubleshooting utility for AWS access issues
*/
class AWSTroubleshooter {
private client: STSClient;
constructor(region: string = "us-east-1") {
this.client = new STSClient({ region });
}
/**
* Diagnose current identity and permissions
*/
async diagnoseIdentity() {
try {
const identity = await this.client.send(new GetCallerIdentityCommand({}));
console.log("Current Identity:");
console.log(` Account: ${identity.Account}`);
console.log(` User ID: ${identity.UserId}`);
console.log(` ARN: ${identity.Arn}`);
// Determine identity type
let identityType = "Unknown";
if (identity.Arn) {
if (identity.Arn.includes(':user/')) identityType = "IAM User";
else if (identity.Arn.includes(':assumed-role/')) identityType = "Assumed Role";
else if (identity.Arn.includes(':federated-user/')) identityType = "Federated User";
else if (identity.Arn.includes(':root')) identityType = "Root User";
}
console.log(` Type: ${identityType}`);
return { success: true, identity, type: identityType };
} catch (error) {
console.error("Failed to get identity:", error);
return { success: false, error: error.message };
}
}
/**
* Decode and analyze authorization failure
*/
async analyzeAuthorizationFailure(encodedMessage: string) {
try {
const command = new DecodeAuthorizationMessageCommand({
EncodedMessage: encodedMessage
});
const response = await this.client.send(command);
const decoded = JSON.parse(response.DecodedMessage || "{}");
console.log("Authorization Failure Analysis:");
console.log(` Action: ${decoded.action}`);
console.log(` Resource: ${decoded.resource}`);
console.log(` Principal: ${decoded.principal}`);
console.log(` Allowed: ${decoded.allowed}`);
if (decoded.context) {
console.log(" Context:");
Object.entries(decoded.context).forEach(([key, value]) => {
console.log(` ${key}: ${value}`);
});
}
// Provide troubleshooting suggestions
this.provideSuggestions(decoded);
return { success: true, decoded };
} catch (error) {
console.error("Failed to decode authorization message:", error);
return { success: false, error: error.message };
}
}
/**
* Provide troubleshooting suggestions based on decoded message
*/
private provideSuggestions(decoded: any) {
console.log("\nTroubleshooting Suggestions:");
if (decoded.allowed === false) {
console.log("• Check if the IAM policy grants the required action");
console.log("• Verify the resource ARN matches what you're trying to access");
console.log("• Check for any Deny statements that might override Allow statements");
}
if (decoded.action && decoded.action.includes("*")) {
console.log("• Wildcard actions may require more specific permissions");
}
if (decoded.resource && decoded.resource.includes("*")) {
console.log("• Wildcard resources may not cover the specific resource you're accessing");
}
if (decoded.context?.aws_RequestedRegion) {
console.log(`• Action was attempted in region: ${decoded.context.aws_RequestedRegion}`);
console.log("• Check if your policy has region restrictions");
}
}
/**
* Comprehensive access key analysis
*/
async analyzeAccessKey(accessKeyId: string) {
try {
const command = new GetAccessKeyInfoCommand({ AccessKeyId: accessKeyId });
const response = await this.client.send(command);
console.log("Access Key Analysis:");
console.log(` Key ID: ${accessKeyId}`);
console.log(` Account: ${response.Account}`);
// Check if it's a valid format
if (!/^AKIA[0-9A-Z]{16}$/.test(accessKeyId)) {
console.warn("• Key ID format appears invalid");
} else {
console.log("• Key ID format is valid");
}
return { success: true, account: response.Account };
} catch (error) {
console.error("Failed to analyze access key:", error);
if (error.name === 'InvalidUserID.NotFound') {
console.log("• The access key does not exist or has been deleted");
}
return { success: false, error: error.message };
}
}
}
// Usage example
const troubleshooter = new AWSTroubleshooter("us-east-1");
// Diagnose current identity
await troubleshooter.diagnoseIdentity();
// Analyze authorization failure
const encodedMessage = "VGhpcyBpcyBhbiBlbmNvZGVkIG1lc3NhZ2U...";
await troubleshooter.analyzeAuthorizationFailure(encodedMessage);
// Analyze access key
await troubleshooter.analyzeAccessKey("AKIAIOSFODNN7EXAMPLE");Utility operations have specific error scenarios to handle:
import {
STSClient,
DecodeAuthorizationMessageCommand,
GetAccessKeyInfoCommand,
InvalidAuthorizationMessageException,
STSServiceException
} from "@aws-sdk/client-sts";
const handleUtilityErrors = async (operation: () => Promise<any>) => {
try {
return await operation();
} catch (error) {
if (error instanceof InvalidAuthorizationMessageException) {
console.error("Authorization message is invalid or malformed");
} else if (error instanceof STSServiceException) {
console.error(`STS Error: ${error.name} - ${error.message}`);
} else {
console.error("Unexpected error:", error);
}
throw error;
}
};
// Safe decode operation
const safeDecodeMessage = async (encodedMessage: string) => {
return handleUtilityErrors(async () => {
const command = new DecodeAuthorizationMessageCommand({
EncodedMessage: encodedMessage
});
return await client.send(command);
});
};
// Safe access key info operation
const safeGetAccessKeyInfo = async (accessKeyId: string) => {
return handleUtilityErrors(async () => {
const command = new GetAccessKeyInfoCommand({
AccessKeyId: accessKeyId
});
return await client.send(command);
});
};