A command-line interface and interactive TUI for accessing EC2 Instance Metadata Service (IMDS) information.
IMDS_VERSION=$(curl -fsSL "https://api.github.com/repos/bwagner5/imds/releases/latest" | grep '"tag_name":' | cut -d'"' -f4 | tr -d 'v')
ARCH=$(dpkg --print-architecture)
curl -fsSL "https://github.com/bwagner5/imds/releases/download/v${IMDS_VERSION}/imds_${IMDS_VERSION}_linux_${ARCH}.deb" -o imds.deb
sudo apt install ./imds.deb
rm imds.debIMDS_VERSION=$(curl -fsSL "https://api.github.com/repos/bwagner5/imds/releases/latest" | grep '"tag_name":' | cut -d'"' -f4 | tr -d 'v')
ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
sudo yum install -y "https://github.com/bwagner5/imds/releases/download/v${IMDS_VERSION}/imds_${IMDS_VERSION}_linux_${ARCH}.rpm"go install github.com/bwagner5/imds/cmd@latestgo build -o imds ./cmd/main.gobrew install bwagner5/wagner/imdsYou can play around with it locally on your mac using the EC2 Metadata Mock.
Launch the interactive explorer by running imds with no arguments:
imdsTUI Features:
- Browse IMDS data in a filesystem-like tree view
- View key descriptions from AWS documentation
- Full-screen value viewer for detailed inspection
- Global search (
/) to find keys across all paths
TUI Navigation:
↑/↓orj/k- NavigateEnterorSpace- Select (enter directory or view value)←/Backspaceorh- Go back/- Search all keysEsc- Cancel search or return to rootq- Quit
Get a specific value using smart lookup (automatically finds the key):
imds instance-id
# Output: i-1234567890abcdef0
imds region
# Output: us-east-1
imds availability-zone
# Output: us-east-1aQuery using explicit paths:
imds placement/region
imds dynamic/instance-identity/documentList all keys recursively (without values):
imds -r
# Output:
# meta-data/
# instance-id
# instance-type
# placement/
# availability-zone
# region
# dynamic/
# instance-identity/
# document
# user-dataDump all keys with their values:
imds --dump
# Output:
# meta-data/
# instance-id: i-1234567890abcdef0
# instance-type: m5.large
# placement/
# availability-zone: us-east-1a
# region: us-east-1Dump a specific path:
imds spot --dump
imds events --dumpExport data as JSON:
# All data
imds --json > imds-data.json
# Specific path
imds events --json
# Specific key
imds instance-id --jsonMonitor IMDS data for changes:
# Watch all data
imds --watch
# Watch specific path (useful for spot termination)
imds spot --watch| Flag | Short | Description |
|---|---|---|
--recursive |
-r |
List all paths recursively (tree, keys only) |
--dump |
-d |
Dump all paths with values |
--json |
-j |
Output as JSON |
--watch |
-w |
Watch for changes |
--endpoint |
-e |
IMDS endpoint (default: http://169.254.169.254) |
--version |
Show version information |
The CLI automatically searches for keys, so you don't need to remember full paths:
imds instance-id # finds meta-data/instance-id
imds region # finds meta-data/placement/region
imds availability-zone # finds meta-data/placement/availability-zone
imds document # finds dynamic/instance-identity/documentIf a key isn't found, similar keys are suggested:
imds instanc-id
# Key "instanc-id" not found. Did you mean:
# - instance-id
# - elastic-inference-accelerator-id| Variable | Description |
|---|---|
IMDS_ENDPOINT |
Override the default IMDS endpoint |
# Launch interactive TUI
imds
# Get instance information
imds instance-id
imds instance-type
imds ami-id
# Get network information
imds local-ipv4
imds public-ipv4
imds mac
# Get placement information
imds region
imds availability-zone
# Get IAM credentials (if available)
imds iam/security-credentials/
# Get instance identity document
imds dynamic/instance-identity/document
# Monitor spot termination
imds spot --watch
# Export all metadata as JSON
imds --json > metadata.json
# View scheduled maintenance events
imds events --dumpThe pkg/imds package can be used programmatically:
package main
import (
"context"
"fmt"
"github.com/bwagner5/imds/pkg/imds"
)
func main() {
ctx := context.Background()
client, _ := imds.NewClient(ctx, "")
// Get a specific value
resp, _ := client.Get(ctx, "meta-data/instance-id")
fmt.Println(string(resp))
// Get all data recursively
data := client.GetAll(ctx, "")
// Find a key by name
path := client.FindKey(ctx, "instance-id")
// Watch for changes
for update := range client.Watch(ctx, "meta-data/spot") {
fmt.Printf("Update: %v\n", update)
}
}