Linux Platform Guide

Complete guide for using Entra Auth Cli on Linux, including secure token storage, distribution-specific installation, and Linux-specific features.

Overview

Entra Auth Cli provides secure token storage and management on Linux:

  • Encrypted Storage: XOR-based encryption with user-specific keys
  • Distribution Support: Works on Ubuntu, Debian, RHEL, Fedora, Arch, and more
  • Container Ready: Optimized for Docker and Kubernetes
  • Shell Integration: Compatible with bash, zsh, fish, and more

Installation

Debian/Ubuntu (APT)

  # Download .deb package
wget https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli_amd64.deb

# Install
sudo dpkg -i entra-auth-cli_amd64.deb

# Or install directly
curl -L https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli_amd64.deb \
  -o /tmp/entra-auth-cli.deb && \
  sudo dpkg -i /tmp/entra-auth-cli.deb

# Verify
entra-auth-cli --version
  

RHEL/CentOS/Fedora (RPM)

  # Download .rpm package
wget https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-1.0.0-1.x86_64.rpm

# Install
sudo rpm -ivh entra-auth-cli-1.0.0-1.x86_64.rpm

# Or use dnf
sudo dnf install https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-1.0.0-1.x86_64.rpm

# Verify
entra-auth-cli --version
  

Arch Linux (AUR)

  # Using yay
yay -S entra-auth-cli

# Using paru
paru -S entra-auth-cli

# Manual from AUR
git clone https://aur.archlinux.org/entra-auth-cli.git
cd entra-auth-cli
makepkg -si
  

Universal Binary

  # Download binary
curl -L https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-linux-amd64 \
  -o /usr/local/bin/entra-auth-cli

# Make executable
chmod +x /usr/local/bin/entra-auth-cli

# Verify
entra-auth-cli --version
  

From Source

  # Prerequisites
sudo apt-get install golang-go  # Debian/Ubuntu
sudo dnf install golang          # Fedora/RHEL
sudo pacman -S go                # Arch

# Clone and build
git clone https://github.com/garrardkitchen/entra-auth-cli.git
cd entra-auth-cli
go build -o entra-auth-cli ./cmd/entra-auth-cli

# Install
sudo mv entra-auth-cli /usr/local/bin/
  

Token Storage

Storage Location

  # Tokens stored in user's home directory
~/.entra-auth-cli/
├── profiles/
│   ├── default.json        # Profile configuration
│   ├── default.token       # Encrypted token
│   ├── production.json
│   └── production.token
└── config.json             # Global configuration

# Check storage
ls -la ~/.entra-auth-cli/profiles/
  

Encryption

Tokens are encrypted using XOR with a user-specific key:

  # Key derived from:
# - User ID (UID)
# - Machine ID (/etc/machine-id)
# - Home directory path

# View machine ID
cat /etc/machine-id

# View user ID
id -u

# Tokens cannot be decrypted:
# - On different machine
# - By different user
# - If machine-id changes
  

File Permissions

  # Verify secure permissions
ls -la ~/.entra-auth-cli/profiles/

# Should show:
# -rw------- (600) - Only owner can read/write
# drwx------ (700) - Only owner can access directory

# Fix permissions if needed
chmod 700 ~/.entra-auth-cli/profiles/
chmod 600 ~/.entra-auth-cli/profiles/*
  

SELinux Context

  # For SELinux-enabled systems (RHEL/CentOS/Fedora)

# Check context
ls -Z ~/.entra-auth-cli/

# Set correct context
chcon -R -t user_home_t ~/.entra-auth-cli/

# Make permanent
semanage fcontext -a -t user_home_t "~/.entra-auth-cli(/.*)?"
restorecon -R ~/.entra-auth-cli/
  

Shell Integration

Bash

  # Add to ~/.bashrc

# Completion
complete -C entra-auth-cli entra-auth-cli

# Aliases
alias et='entra-auth-cli'
alias etg='entra-auth-cli get-token'
alias etp='entra-auth-cli list-profiles'

# Function to get token
get_token() {
    local profile="${1:-default}"
    entra-auth-cli get-token --profile "$profile" --output json | jq -r .access_token
}

# Function to export token
export_token() {
    local profile="${1:-default}"
    export ENTRA_TOKEN=$(get_token "$profile")
    echo "Token exported to \$ENTRA_TOKEN"
}

# Graph API helper
graph() {
    local endpoint="$1"
    local token=$(get_token)
    curl -s -H "Authorization: Bearer $token" \
      "https://graph.microsoft.com/v1.0/$endpoint" | jq .
}
  

Zsh

  # Add to ~/.zshrc

# Completion
autoload -U compinit && compinit
complete -o nospace -C entra-auth-cli entra-auth-cli

# Aliases
alias et='entra-auth-cli'
alias etg='entra-auth-cli get-token'

# Functions
get_token() {
    entra-auth-cli get-token --profile "${1:-default}" --output json | jq -r .access_token
}

# Prompt integration (show if token is valid)
precmd() {
    if entra-auth-cli inspect &>/dev/null; then
        RPROMPT="%F{green}🔑%f"
    else
        RPROMPT="%F{red}🔑%f"
    fi
}
  

Fish

  # Add to ~/.config/fish/config.fish

# Completion
complete -c entra-auth-cli -f

# Aliases
alias et='entra-auth-cli'
alias etg='entra-auth-cli get-token'

# Function
function get_token
    set -l profile (test -n "$argv[1]"; and echo $argv[1]; or echo "default")
    entra-auth-cli get-token --profile $profile --output json | jq -r .access_token
end

# Export function
function export_token
    set -l profile (test -n "$argv[1]"; and echo $argv[1]; or echo "default")
    set -gx ENTRA_TOKEN (get_token $profile)
    echo "Token exported to \$ENTRA_TOKEN"
end
  

Linux-Specific Features

Systemd Service

  # /etc/systemd/system/entra-auth-cli-refresh.service
[Unit]
Description=Entra Auth Cli Token Refresh
After=network.target

[Service]
Type=oneshot
User=%i
ExecStart=/usr/local/bin/entra-auth-cli refresh --profile production
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
  
  # /etc/systemd/system/entra-auth-cli-refresh.timer
[Unit]
Description=Refresh Entra tokens hourly
Requires=entra-auth-cli-refresh.service

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
Unit=entra-auth-cli-refresh.service

[Install]
WantedBy=timers.target
  
  # Enable and start
sudo systemctl daemon-reload
sudo systemctl enable entra-auth-cli-refresh@$USER.timer
sudo systemctl start entra-auth-cli-refresh@$USER.timer

# Check status
systemctl status entra-auth-cli-refresh@$USER.timer
systemctl list-timers --all | grep entra-auth-cli

# View logs
journalctl -u entra-auth-cli-refresh@$USER.service
  

Cron Jobs

  # Add to crontab
crontab -e

# Refresh token every hour
0 * * * * /usr/local/bin/entra-auth-cli refresh --profile production >> /var/log/entra-auth-cli-refresh.log 2>&1

# Refresh at specific times
0 8,12,17 * * * /usr/local/bin/entra-auth-cli refresh --profile work

# With environment
0 * * * * . $HOME/.profile; /usr/local/bin/entra-auth-cli refresh --profile production
  

Environment Modules

  # For HPC/cluster environments with environment modules

# /opt/modulefiles/entra-auth-cli/1.0
#%Module1.0
proc ModulesHelp { } {
    puts stderr "Entra Auth Cli - Microsoft Entra ID token management"
}

module-whatis "Microsoft Entra ID token management tool"

prepend-path PATH /opt/entra-auth-cli/bin
setenv ENTRA_TOKEN_HOME /opt/entra-auth-cli

# Load module
module load entra-auth-cli
  

Container Integration

Docker

  FROM ubuntu:22.04

# Install dependencies
RUN apt-get update && \
    apt-get install -y curl jq && \
    rm -rf /var/lib/apt/lists/*

# Install Entra Auth Cli
RUN curl -L https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-linux-amd64 \
    -o /usr/local/bin/entra-auth-cli && \
    chmod +x /usr/local/bin/entra-auth-cli

# Create non-root user
RUN useradd -m -s /bin/bash appuser
USER appuser

# Set up profiles directory
RUN mkdir -p /home/appuser/.entra-auth-cli/profiles

# Copy entrypoint
COPY entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
  
  #!/bin/bash
# entrypoint.sh

# Create profile from environment variables
if [ -n "$TENANT_ID" ] && [ -n "$CLIENT_ID" ] && [ -n "$CLIENT_SECRET" ]; then
    entra-auth-cli create-profile \
        --name container \
        --tenant-id "$TENANT_ID" \
        --client-id "$CLIENT_ID" \
        --client-secret "$CLIENT_SECRET" \
        --scope "${SCOPE:-https://graph.microsoft.com/.default}"
fi

# Get token
export TOKEN=$(entra-auth-cli get-token --profile container --output json | jq -r .access_token)

# Execute main command
exec "$@"
  

Kubernetes

  apiVersion: v1
kind: ConfigMap
metadata:
  name: entra-auth-cli-config
data:
  create-profile.sh: |
    #!/bin/bash
    entra-auth-cli create-profile \
      --name k8s \
      --tenant-id "$TENANT_ID" \
      --client-id "$CLIENT_ID" \
      --client-secret "$CLIENT_SECRET"
---
apiVersion: v1
kind: Secret
metadata:
  name: azure-credentials
type: Opaque
stringData:
  tenant-id: "your-tenant-id"
  client-id: "your-client-id"
  client-secret: "your-client-secret"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-entra-auth-cli
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: myapp:latest
        env:
        - name: TENANT_ID
          valueFrom:
            secretKeyRef:
              name: azure-credentials
              key: tenant-id
        - name: CLIENT_ID
          valueFrom:
            secretKeyRef:
              name: azure-credentials
              key: client-id
        - name: CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              name: azure-credentials
              key: client-secret
        volumeMounts:
        - name: entra-auth-cli-config
          mountPath: /config
        command:
        - /bin/bash
        - -c
        - |
          /config/create-profile.sh
          TOKEN=$(entra-auth-cli get-token --output json | jq -r .access_token)
          export AUTH_TOKEN=$TOKEN
          exec /app/start.sh
      volumes:
      - name: entra-auth-cli-config
        configMap:
          name: entra-auth-cli-config
          defaultMode: 0755
  

Common Use Cases

CI/CD Integration

GitLab CI

  # .gitlab-ci.yml
stages:
  - deploy

deploy:
  stage: deploy
  image: ubuntu:22.04
  before_script:
    - apt-get update && apt-get install -y curl jq
    - curl -L https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-linux-amd64 
        -o /usr/local/bin/entra-auth-cli
    - chmod +x /usr/local/bin/entra-auth-cli
    - |
      entra-auth-cli create-profile \
        --name ci \
        --tenant-id "$AZURE_TENANT_ID" \
        --client-id "$AZURE_CLIENT_ID" \
        --client-secret "$AZURE_CLIENT_SECRET"
  script:
    - TOKEN=$(entra-auth-cli get-token --profile ci --output json | jq -r .access_token)
    - echo "Deploying with token..."
    - curl -H "Authorization: Bearer $TOKEN" https://api.example.com/deploy
  only:
    - main
  

Jenkins

  // Jenkinsfile
pipeline {
    agent any
    
    environment {
        TENANT_ID = credentials('azure-tenant-id')
        CLIENT_ID = credentials('azure-client-id')
        CLIENT_SECRET = credentials('azure-client-secret')
    }
    
    stages {
        stage('Setup') {
            steps {
                sh '''
                    curl -L https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-linux-amd64 \
                      -o /tmp/entra-auth-cli
                    chmod +x /tmp/entra-auth-cli
                    sudo mv /tmp/entra-auth-cli /usr/local/bin/
                '''
            }
        }
        
        stage('Authenticate') {
            steps {
                sh '''
                    entra-auth-cli create-profile \
                      --name jenkins \
                      --tenant-id "$TENANT_ID" \
                      --client-id "$CLIENT_ID" \
                      --client-secret "$CLIENT_SECRET"
                '''
            }
        }
        
        stage('Deploy') {
            steps {
                sh '''
                    TOKEN=$(entra-auth-cli get-token --profile jenkins --output json | jq -r .access_token)
                    curl -H "Authorization: Bearer $TOKEN" https://api.example.com/deploy
                '''
            }
        }
    }
}
  

SSH Remote Execution

  # Execute on remote server with token
ssh user@server "$(cat <<'EOF'
TOKEN=$(entra-auth-cli get-token --profile production --output json | jq -r .access_token)
curl -H "Authorization: Bearer $TOKEN" https://graph.microsoft.com/v1.0/me
EOF
)"

# Deploy profile to remote server
scp ~/.entra-auth-cli/profiles/production.* user@server:~/.entra-auth-cli/profiles/

# Execute script remotely
ssh user@server 'bash -s' < local-script.sh
  

Ansible Playbook

  # playbook.yml
---
- name: Deploy application with Entra Token
  hosts: webservers
  tasks:
    - name: Install Entra Auth Cli
      get_url:
        url: https://github.com/garrardkitchen/entra-auth-cli/releases/latest/download/entra-auth-cli-linux-amd64
        dest: /usr/local/bin/entra-auth-cli
        mode: '0755'
      become: yes

    - name: Create profile
      shell: |
        entra-auth-cli create-profile \
          --name ansible \
          --tenant-id "{{ azure_tenant_id }}" \
          --client-id "{{ azure_client_id }}" \
          --client-secret "{{ azure_client_secret }}"
      no_log: true

    - name: Get token
      shell: entra-auth-cli get-token --profile ansible --output json
      register: token_output

    - name: Deploy application
      uri:
        url: https://api.example.com/deploy
        method: POST
        headers:
          Authorization: "Bearer {{ (token_output.stdout | from_json).access_token }}"
        body_format: json
  

Security Best Practices

File System Permissions

  # Secure home directory
chmod 700 ~

# Secure entra-auth-cli directory
chmod 700 ~/.entra-auth-cli
chmod 700 ~/.entra-auth-cli/profiles
chmod 600 ~/.entra-auth-cli/profiles/*

# Verify
ls -la ~/.entra-auth-cli/profiles/
  

AppArmor Profile

  # /etc/apparmor.d/usr.local.bin.entra-auth-cli
#include <tunables/global>

/usr/local/bin/entra-auth-cli {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  #include <abstractions/ssl_certs>

  /usr/local/bin/entra-auth-cli mr,
  
  owner @{HOME}/.entra-auth-cli/ rw,
  owner @{HOME}/.entra-auth-cli/** rw,
  
  /etc/machine-id r,
  /proc/sys/kernel/random/uuid r,
  
  network inet stream,
  network inet6 stream,
}

# Load profile
sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.entra-auth-cli
  

Firewall Rules

  # Allow outbound HTTPS to Microsoft Entra ID
sudo ufw allow out 443/tcp

# Restrict to Microsoft IPs (optional)
sudo iptables -A OUTPUT -p tcp -d login.microsoftonline.com --dport 443 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 443 -j DROP
  

Troubleshooting

Permission Denied

Problem: Cannot read/write token files

Solutions:

  # Check ownership
ls -la ~/.entra-auth-cli/profiles/

# Fix ownership
chown -R $USER:$USER ~/.entra-auth-cli/

# Fix permissions
chmod 700 ~/.entra-auth-cli/profiles/
chmod 600 ~/.entra-auth-cli/profiles/*
  

Machine ID Changed

Problem: “Cannot decrypt token” after system reinstall

Solution:

  # Machine ID changed, tokens are invalid
# Delete old tokens and re-authenticate
rm ~/.entra-auth-cli/profiles/*.token

# Get new token
entra-auth-cli get-token --flow interactive
  

SELinux Denial

Problem: SELinux blocks token access

Solutions:

  # Check denials
sudo ausearch -m avc -ts recent | grep entra-auth-cli

# Allow access
sudo audit2allow -a -M entra-auth-cli
sudo semodule -i entra-auth-cli.pp

# Or set correct context
sudo chcon -R -t user_home_t ~/.entra-auth-cli/
  

Missing Dependencies

Problem: “jq: command not found”

Solutions:

  # Ubuntu/Debian
sudo apt-get install jq

# RHEL/CentOS/Fedora
sudo dnf install jq

# Arch
sudo pacman -S jq
  

Performance Optimization

Token Caching

  # Cache token in tmpfs (RAM disk)
CACHE_DIR="/dev/shm/entra-auth-cli-$$"
mkdir -p "$CACHE_DIR"
chmod 700 "$CACHE_DIR"

# Get and cache token
entra-auth-cli get-token --output json > "$CACHE_DIR/token.json"

# Use cached token
TOKEN=$(jq -r .access_token "$CACHE_DIR/token.json")

# Cleanup on exit
trap "rm -rf $CACHE_DIR" EXIT
  

Parallel Processing

  # Parallel API calls with GNU parallel
TOKEN=$(entra-auth-cli get-token --output json | jq -r .access_token)

parallel -j 10 "curl -s -H 'Authorization: Bearer $TOKEN' {}" ::: \
  https://graph.microsoft.com/v1.0/users \
  https://graph.microsoft.com/v1.0/groups \
  https://graph.microsoft.com/v1.0/applications \
  | jq -s .
  

Next Steps