ββββββββββ βββββββ βββ ββββββββββ βββββββββββββββββββ
βββββββββββ ββββββββββββ βββββββββββββββββββββββββββββββ
βββ βββ βββ ββββββ ββββββ ββββββ βββ βββ
βββ βββ βββ ββββββ ββββββ ββββββ βββ βββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ βββ ββββββββ
βββββββββββββββ βββββββ βββββββ βββββββ βββββββ βββ ββββββββ
A lightweight CLI tool for securely managing AWS AssumeRole sessions with MFA support and encrypted credential storage.
- π Secure Credential Storage - Encrypt AWS credentials with AES-256-GCM
- π― AssumeRole Support - Easily assume IAM roles with MFA
- π¨ Enhanced Gradient CLI - Beautiful 24-bit color gradient UI
- π€ Auto-Refresh Daemon - Background service with self-forking, daily log rotation, and macOS LaunchAgent support
- π Role Aliasing - Bulk import/export IAM roles via JSON
- π Console Access - Generate AWS console URLs instantly
- π§© Hybrid Login - Reuse existing sessions as source for role assumption
- ποΈ Smart Sync - Export sessions to
~/.aws/credentialswith session type tracking - π Intelligent Batch Refresh - Refresh all sessions at once; restores expired sources with a single MFA prompt
- πΉπ Bangkok Timezone - All displays and logs standardized to BKK (UTC+7) time
- Interactive TUI: Modern, interactive prompts sorted alphabetically (A-Z) for easy selection.
- Touch ID Support: Securely store encryption keys in macOS Keychain for passwordless operation.
- MFA Session Caching: Enter MFA once, assume unlimited roles for 12 hours.
- π Shell Integration - Display current session and remaining time in your shell prompt.
- π Masked MFA Input - Asterisk display (
******) for MFA codes with backspace support. - π‘οΈ Session Persistence - Automatically tracks AWS Region to ensure correct API calls during refresh.
- Go 1.22 or higher
- AWS CLI configured with at least one profile
- Valid AWS credentials
# Add the tap
brew tap chukul/homebrew-tap
# Install cloudctl
brew install cloudctl# Clone the repository
git clone https://github.com/chukul/cloudctl.git
cd cloudctl
# Build the binary
go build
# (Optional) Move to PATH
sudo mv cloudctl /usr/local/bin/Set up shell integration for the best experience:
# Generate and add to your shell config
cloudctl init >> ~/.zshrc # or ~/.bashrc for Bash
# Edit ~/.zshrc and set your encryption secret
export CLOUDCTL_SECRET="your-32-char-encryption-key"
# Reload your shell
source ~/.zshrcAfter setup, you get:
ccs <profile>- Quick switch without evalccl- Alias for cloudctl loginccst- Alias for cloudctl statusccr- Alias for cloudctl refreshccc- Alias for cloudctl consoleccm- Alias for cloudctl mfa-login- Shell prompt showing current session and remaining time
If you need to assume multiple roles with MFA, get an MFA session first:
# Step 1: Get MFA session once (valid for 12 hours)
cloudctl mfa-login \
--source default \
--profile mfa-session \
--mfa arn:aws:iam::123456789012:mfa/username
# Enter MFA code when prompted (displays as ******)
# Step 2: Use MFA session to assume multiple roles (no MFA needed!)
cloudctl login --source mfa-session --profile prod-admin --role arn:aws:iam::123456789012:role/AdminRole
cloudctl login --source mfa-session --profile dev-readonly --role arn:aws:iam::123456789012:role/ReadOnlyRole
cloudctl login --source mfa-session --profile staging --role arn:aws:iam::987654321098:role/StagingRoleAssume an IAM role and store the credentials securely:
cloudctl login \
--source <source-profile> \
--profile <session-name> \
--role <role-arn> \
--secret "your-32-char-encryption-key" \
--region ap-southeast-1Example:
cloudctl login \
--source default \
--profile prod-admin \
--role arn:aws:iam::123456789012:role/AdminRole \
--secret "1234567890ABCDEF1234567890ABCDEF"With MFA (single role):
cloudctl login \
--source default \
--profile prod-admin \
--role arn:aws:iam::123456789012:role/AdminRole \
--mfa arn:aws:iam::123456789012:mfa/username \
--secret "1234567890ABCDEF1234567890ABCDEF"With auto-open console:
cloudctl login \
--source mfa-session \
--profile uat_ca \
--role arn:aws:iam::814348778342:role/CIMBTH_CloudAdministrator \
--openList all stored sessions with their status:
cloudctl status --secret "1234567890ABCDEF1234567890ABCDEF"Output:
Active Sessions
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π’ prod-admin β current AdminRole (123456789012) 45m remaining
Source: 5358609 Expires: 2025-11-20 10:30:00
π mfa-session MFA Session 11h45m remaining
Expires: 2025-11-20 22:30:00
Expiring Soon
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π‘ staging DevOpsRole (987654321098) 12m remaining
Source: mfa-session Expires: 2025-11-20 09:42:00
Status Icons:
- π’ Green (ACTIVE) - Session has more than 15 minutes remaining
- π‘ Yellow (EXPIRING) - Session expires in 15 minutes or less
- π΄ Red (EXPIRED) - Session has expired
- π Lock (MFA SESSION) - MFA session token
Fast profile switching with one command:
# Set your secret once
export CLOUDCTL_SECRET="1234567890ABCDEF1234567890ABCDEF"
# Switch to any profile instantly
eval $(cloudctl switch prod-admin)
eval $(cloudctl switch dev-readonly)
# Or use the shell function (if init is configured)
ccs prod-admin
# Verify
aws sts get-caller-identityImportant: Unset AWS_PROFILE if it's already set in your environment:
unset AWS_PROFILE
eval $(cloudctl switch prod-admin)Keep your sessions alive or restore expired ones using stored metadata. cloudctl will automatically decide between a silent refresh or an interactive MFA-based restore. Using --all enables Intelligent Batch Refresh, which restores expired source sessions (like MFA sessions) once and then automatically silent-refreshes all dependent role sessions.
# Smart refresh interactively (Sorted A-Z)
cloudctl refresh
# Refresh specific profile
cloudctl refresh prod-admin
# Force interactive re-login even if still active
cloudctl refresh prod-admin --force
# Silent refresh for all active sessions (Used by Daemon)
# Automatically syncs results to credentials file upon success.
cloudctl refresh --allKeep your sessions alive automatically. The daemon tracks the Region of each session to perform silent refreshes and automatically syncs updated credentials to ~/.aws/credentials.
# 1. Setup automatic startup (macOS only)
cloudctl daemon setup
launchctl load ~/Library/LaunchAgents/com.chukul.cloudctl.plist
# 2. Start (Runs in background automatically via self-forking)
cloudctl daemon start
# 3. View status and logs
cloudctl daemon status
cloudctl daemon logs
# 4. Stop
cloudctl daemon stop
# 5. Run in foreground (for debugging)
cloudctl daemon start --foregroundSee Smart Refresh & Restore for detailed usage.
Remove stored credentials:
# Remove specific profile
cloudctl logout --profile prod-admin
# Remove all profiles
cloudctl logout --allOn macOS, cloudctl can store your encryption key securely in the System Keychain.
This allows you to use cloudctl without manually setting the CLOUDCTL_SECRET environment variable.
- Run
cloudctl login(or any command) without a secret. - Follow the prompt to generate and store a secure key.
- Future commands will use Touch ID / User Password to unlock the key automatically.
Since your credentials are encrypted, you must backup your key!
# Reveal your key (requires Touch ID)
cloudctl secret show
# Save the output to your password managerTo restore on a new machine (or if you reinstall OS):
# Import your backed-up key into Keychain
cloudctl secret import <your-key>Save frequently used IAM Roles with friendly aliases.
# Add a role alias
cloudctl role add prod-admin arn:aws:iam::123456789012:role/ProductionAdmin
# List saved roles
cloudctl role list
# Export roles to JSON
cloudctl role export all-roles.json
# Import roles from JSON (Bulk onboarding)
cloudctl role import all-roles.json
# Use alias in login
cloudctl login --source default --profile prod --role prod-adminSave your MFA devices with friendly names to avoid typing ARNs.
# Add a device alias
cloudctl mfa add iphone arn:aws:iam::123456789012:mfa/my-user
# List saved devices
cloudctl mfa list
# Use alias in login
cloudctl mfa-login --mfa iphoneExport your active cloudctl sessions to ~/.aws/credentials. The command identifies whether a session is a Role or MFA session in the comments.
# Interactive sync with session type labeling (MFA or Role)
cloudctl sync
# Sync all active sessions without prompt
cloudctl sync --all
# Sync specific profile
cloudctl sync --profile prod-adminNote: cloudctl automatically performs a sync after any successful refresh --all or when the background daemon updates a session. Manual sync is only needed if you want to export a specific single profile or if you aren't using the automation features. cloudctl automatically detects your secret from macOS Keychain or environment variables. No --secret flag needed if setup.
Get MFA session token to use for multiple role assumptions.
Flags:
--source- Source AWS CLI profile for base credentials (required)--profile- Name to store the MFA session as (required)--mfa- MFA device ARN (required)--secret- Encryption key for credential storage (or set CLOUDCTL_SECRET env var)--duration- Session duration in seconds (default: 43200 = 12 hours, max: 129600 = 36 hours)
Usage:
# Get MFA session (valid for 12 hours)
cloudctl mfa-login --source default --profile mfa-session --mfa arn:aws:iam::123:mfa/user
# Use MFA session to assume roles without re-entering MFA
cloudctl login --source mfa-session --profile role1 --role arn:aws:iam::123:role/Role1
cloudctl login --source mfa-session --profile role2 --role arn:aws:iam::456:role/Role2Assume an AWS role and store credentials locally.
Flags:
--source- Source AWS CLI profile or cloudctl session for base credentials (required)--profile- Name to store the new session as (required)--role- Target IAM role ARN to assume (required)--mfa- MFA device ARN (optional)--secret- Encryption key for credential storage (or set CLOUDCTL_SECRET env var)--region- AWS region (default: ap-southeast-1)--open- Automatically open AWS Console after successful login--duration- Session duration in seconds (default: 3600 = 1 hr, max: 43200 = 12 hrs)
Usage:
# Basic login
cloudctl login --source default --profile prod --role arn:aws:iam::123:role/Admin
# With MFA
cloudctl login --source default --profile prod --role arn:aws:iam::123:role/Admin --mfa arn:aws:iam::123:mfa/user
# With auto-open console
cloudctl login --source mfa-session --profile prod --role arn:aws:iam::123:role/Admin --openShow all stored AWS sessions with enhanced visual display.
Features:
- Status icons: π’ Active | π‘ Expiring | π΄ Expired | π MFA Session
- Grouped by status (Active β Expiring β Expired)
- Account ID and role name extraction for cleaner display
- Current session highlighting (β current)
- Helpful onboarding message when no sessions exist
Flags:
--secret- Encryption key to decrypt credentials (or set CLOUDCTL_SECRET env var)
Usage:
cloudctl status
# or
ccst # if shell integration is configuredExample Output:
Active Sessions
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π’ prod-admin β current AdminRole (123456789012) 45m remaining
Expires: 2025-11-20 10:30:00
π mfa-session MFA Session 11h45m remaining
Expires: 2025-11-20 22:30:00
Expiring Soon
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π‘ staging DevOpsRole (987654321098) 12m remaining
Expires: 2025-11-20 09:42:00
Quick switch to a profile and export credentials. Only active (non-expired) sessions are shown in the interactive list.
Usage:
# Interactive selection (Sorted A-Z, filtering out expired ones)
eval $(cloudctl switch)
# Specific profile
eval $(cloudctl switch prod-admin)Generate AWS Console sign-in URL from stored session.
Usage:
# Interactive mode (select from active profiles)
cloudctl console --open
# Specific profile
cloudctl console --profile prod-admin --openNote: MFA sessions cannot be used for console access. Use an assumed role profile instead.
Smart refresh or restore AWS sessions. It re-uses stored metadata (Source, Role, MFA, Region) to renew credentials.
Logic:
- Active Session: Attempts silent refresh without prompt.
- Expired/MFA Session: Prompts for MFA token and performs a full re-login.
- Intelligent Batch: When using
--all, CloudCtl groups profiles by source. If a source is expired, it asks to restore it once, then uses that new session to silently refresh all roles associated with it.
Flags:
--all- Intelligent batch refresh (silent refresh active ones, prompt once per expired source).--profile- Specific profile to refresh.--force(-f) - Force interactive re-login even if session is still active.--secret- Encryption key for decryption.
Usage:
# Interactive smart selection
cloudctl refresh
# Specific profile
cloudctl refresh prod-admin
# Silent refresh all (best for automation)
cloudctl refresh --allGenerate shell integration code for easy setup.
Usage:
# Add to your shell config
cloudctl init >> ~/.zshrc
# Or view the output
cloudctl initWhat it provides:
ccs <profile>- Quick switch function without evalccl- Alias for cloudctl loginccst- Alias for cloudctl statusccr- Alias for cloudctl refreshccc- Alias for cloudctl consoleccm- Alias for cloudctl mfa-login- Shell prompt integration showing current session
- CLOUDCTL_SECRET environment variable setup
Display current session info for shell prompt integration.
Subcommands:
cloudctl prompt- Display formatted prompt string (e.g., βοΈ prod-admin (45m))cloudctl prompt info- Display detailed session info in JSON formatcloudctl prompt setup- Show shell integration setup instructions
Flags:
--secret- Encryption key to decrypt credentials (or set CLOUDCTL_SECRET env var)
Usage:
# In your shell prompt (PS1 or PROMPT)
$(cloudctl prompt)
# Get detailed info
cloudctl prompt infoRemove stored credentials.
Flags:
--profile- Profile to remove--all- Remove all profiles
Usage:
# Remove specific profile
cloudctl logout --profile prod-admin
# Remove all profiles
cloudctl logout --allCloudCtl uses AES-256-GCM encryption for storing credentials. Your encryption key should be:
- Exactly 32 characters long
- Kept secure and not shared
- The same key must be used for storing and retrieving credentials
Example key generation:
# Generate a random 32-character key
openssl rand -hex 16Set as environment variable:
export CLOUDCTL_SECRET="1234567890ABCDEF1234567890ABCDEF"Credentials are stored in:
~/.cloudctl/credentials.json # Encrypted credentials
~/.cloudctl/sessions/ # Session files
These files contain encrypted credentials and should be kept secure.
- Use Strong Encryption Keys - Generate random 32-character keys
- Don't Commit Secrets - Never commit your encryption key or credentials
- Rotate Sessions - Regularly refresh your assumed role sessions
- Use MFA - Enable MFA for sensitive role assumptions
- Limit Session Duration - Use appropriate session durations (default: 1 hour for roles, 12 hours for MFA)
- Secure Storage - Ensure
~/.cloudctl/directory has proper permissions (0700)
CloudCtl provides helpful error messages with troubleshooting tips. Here are common scenarios:
This error occurs when AWS_PROFILE is set in your environment. Unset it:
unset AWS_PROFILE
eval $(cloudctl switch prod-admin)CloudCtl will automatically list available AWS profiles and cloudctl sessions:
β Profile 'default' not found
π‘ Available AWS profiles:
β’ prod
β’ dev
β’ staging
π‘ To create a new profile:
aws configure --profile defaultThe encryption key used for decryption doesn't match the one used for encryption. Ensure you're using the same 32-character key.
CloudCtl provides detailed troubleshooting:
β Failed to assume role: AccessDenied
π‘ Common issues:
β’ Check the role ARN is correct
β’ Verify the role's trust policy allows your source identity
β’ Ensure your source credentials have sts:AssumeRole permission
β’ Check if the role requires MFA (use --mfa flag)CloudCtl shows helpful tips:
β MFA authentication failed
π‘ Common issues:
β’ Check your MFA code is current (not expired)
β’ Verify MFA device ARN is correct
β’ Ensure device time is synchronized
β’ MFA ARN format: arn:aws:iam::<account-id>:mfa/<username>- Check that you're using an assumed role profile (not an MFA session)
- Verify the session hasn't expired
- Ensure your browser is set as the default application for URLs
When running cloudctl status with no sessions, you'll see:
π No stored sessions found.
π‘ Get started:
cloudctl mfa-login --source <profile> --profile mfa-session --mfa <mfa-arn>
cloudctl login --source <profile> --profile <name> --role <role-arn>cloudctl/
βββ cmd/ # Command implementations
β βββ console.go # Console sign-in command
β βββ daemon.go # Auto-refresh daemon
β βββ init.go # Shell integration command
β βββ login.go # Login/assume role command
β βββ logout.go # Logout command
β βββ mfa.go # MFA device alias management
β βββ mfa-login.go # MFA session command
β βββ prompt.go # Shell prompt command
β βββ refresh.go # Smart refresh/restore command
β βββ role.go # Role alias management
β βββ root.go # Root command and CLI setup
β βββ status.go # Status command
β βββ switch.go # Quick switch command
β βββ sync.go # Credentials file sync
β βββ utils.go # Shared utilities (MFA input)
βββ internal/ # Internal packages
β βββ aws.go # AWS SDK helpers
β βββ crypto.go # Encryption/decryption logic
β βββ keychain_darwin.go # macOS Keychain integration
β βββ keychain_stub.go # Stub for non-macOS platforms
β βββ os_utils.go # OS-specific utilities
β βββ session.go # Session types and handling
β βββ storage.go # Credential storage logic
β βββ time_utils.go # Standardized BKK timezone and formatting
β βββ types.go # Shared type definitions
β βββ ui/ # Interactive UI components
βββ go.mod
βββ go.sum
βββ main.go
βββ README.md
# Build for current platform
go build
# Build for specific platform
GOOS=linux GOARCH=amd64 go build -o cloudctl-linux
GOOS=darwin GOARCH=arm64 go build -o cloudctl-macos
GOOS=windows GOARCH=amd64 go build -o cloudctl.exe# Run tests
go test ./...
# Run with coverage
go test -cover ./...Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is open source and available under the MIT License.
Chuchai Kultanahiran
Email: pong2day@gmail.com
- Inspired by Leapp
- Built with Cobra CLI framework
- Uses AWS SDK for Go v2
For issues, questions, or contributions, please visit:
- GitHub Issues: https://github.com/chukul/cloudctl/issues
- GitHub Repository: https://github.com/chukul/cloudctl