{"id":29131314,"url":"https://github.com/locus313/ssh-key-sync","last_synced_at":"2025-10-06T00:56:28.589Z","repository":{"id":300536232,"uuid":"1006413444","full_name":"locus313/ssh-key-sync","owner":"locus313","description":"Robust Bash script for automating SSH authorized_keys synchronization from multiple sources with enterprise-grade reliability","archived":false,"fork":false,"pushed_at":"2025-09-17T07:45:50.000Z","size":112,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-28T14:58:21.363Z","etag":null,"topics":["authorized-keys","key-management","ssh","ssh-keys"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/locus313.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-22T07:59:05.000Z","updated_at":"2025-09-17T08:08:29.000Z","dependencies_parsed_at":"2025-07-21T01:21:18.806Z","dependency_job_id":null,"html_url":"https://github.com/locus313/ssh-key-sync","commit_stats":null,"previous_names":["locus313/ssh-key-sync"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/locus313/ssh-key-sync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locus313%2Fssh-key-sync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locus313%2Fssh-key-sync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locus313%2Fssh-key-sync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locus313%2Fssh-key-sync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/locus313","download_url":"https://codeload.github.com/locus313/ssh-key-sync/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locus313%2Fssh-key-sync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278542675,"owners_count":26004061,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorized-keys","key-management","ssh","ssh-keys"],"created_at":"2025-06-30T05:07:37.201Z","updated_at":"2025-10-06T00:56:28.583Z","avatar_url":"https://github.com/locus313.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SSH Key Sync\n\n[![CI Status](https://img.shields.io/github/actions/workflow/status/locus313/ssh-key-sync/ci.yml?style=flat-square\u0026label=CI)](https://github.com/locus313/ssh-key-sync/actions)\n[![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)\n[![Bash](https://img.shields.io/badge/Bash-5.0+-green?style=flat-square\u0026logo=gnu-bash)](https://www.gnu.org/software/bash/)\n[![Version](https://img.shields.io/badge/Version-0.1.5-orange?style=flat-square)](https://github.com/locus313/ssh-key-sync/releases)\n\n*Synchronize SSH authorized_keys for multiple users from various sources*\n\n⭐ If you like this project, star it on GitHub — it helps a lot!\n\n[Features](#features) • [Getting Started](#getting-started) • [Configuration](#configuration) • [Usage](#usage) • [Examples](#examples) • [Automation](#automation) • [Testing](#testing)\n\nA robust and secure Bash script for automating SSH `authorized_keys` synchronization across multiple users from various sources. Perfect for managing SSH access in development environments, CI/CD pipelines, and production systems with enterprise-grade reliability.\n\n## Features\n\n- **Multi-Source Support** - Fetch SSH keys from public URLs, private GitHub repositories, or GitHub user profiles\n- **Enterprise-Grade Reliability** - Built-in retry mechanism with configurable delays for network resilience  \n- **Atomic Operations** - Safe file updates with comparison checks to prevent unnecessary changes\n- **Comprehensive Audit Trail** - Detailed timestamped logs for monitoring, debugging, and compliance\n- **Self-Maintenance** - Automatic updates to the latest version from GitHub repository\n- **Configuration-as-Code** - External configuration file for version control and team collaboration\n- **Defensive Programming** - Robust error handling with graceful fallbacks and validation\n- **Multi-User Architecture** - Concurrent SSH key management for multiple system users\n- **Security-First Design** - Proper file permissions, user validation, and secure temporary file handling\n\n## Getting Started\n\n### Prerequisites\n\n- **Bash 4.0+** - Required for associative arrays support\n- **curl** - For HTTP operations and API communication\n- **getent** - User information retrieval (standard on most Linux distributions)\n- **GitHub Token** - Only required for accessing private repositories\n\n\u003e [!TIP]\n\u003e You can test the script locally without any external dependencies by using the `raw` method with publicly accessible SSH key files.\n\n### Quick Start\n\n1. **Download the script and configuration**:\n   ```bash\n   # Get the latest release\n   curl -fsSL https://raw.githubusercontent.com/locus313/ssh-key-sync/main/sync-ssh-keys.sh -o sync-ssh-keys.sh\n   curl -fsSL https://raw.githubusercontent.com/locus313/ssh-key-sync/main/users.conf -o users.conf\n   chmod +x sync-ssh-keys.sh\n   ```\n\n2. **Configure your users and key sources**:\n   ```bash\n   # Edit the configuration file\n   nano users.conf\n   \n   # Example configuration\n   declare -A USER_KEYS=(\n     [\"alice\"]=\"ghuser:alice-github\"\n     [\"bob\"]=\"raw:https://example.com/bob.keys\"\n   )\n   ```\n\n3. **Run the synchronization**:\n   ```bash\n   # Test the configuration first\n   sudo ./sync-ssh-keys.sh\n   \n   # Check the logs for successful synchronization\n   ```\n\n4. **Verify the setup**:\n   ```bash\n   # Check that keys were properly synchronized\n   sudo cat /home/alice/.ssh/authorized_keys\n   ```\n\n## Configuration\n\nConfiguration is managed through the `users.conf` file, which defines users and their SSH key sources.\n\n### Configuration Format\n\n```bash\n# Optional: GitHub token for private repository access\nCONF_GITHUB_TOKEN=\"your_github_token_here\"\n\n# User key mapping\ndeclare -A USER_KEYS=(\n  [\"username\"]=\"method:target\"\n)\n```\n\n### Supported Methods\n\n| Method | Description | Use Case | Authentication |\n|--------|-------------|----------|----------------|\n| `raw` | Direct HTTP(S) URL | Public key repositories, CDNs | None |\n| `api` | GitHub API endpoint | Private repositories, enterprise | GitHub Token |\n| `ghuser` | GitHub user profile | Individual developer keys | None |\n\n\u003e [!NOTE]\n\u003e The `ghuser` method fetches public keys from `https://github.com/username.keys`, which is a built-in GitHub feature for accessing any user's public SSH keys.\n\n### Example Configuration\n\n```bash\n#!/bin/bash\n\n# GitHub token for API access (optional)\nCONF_GITHUB_TOKEN=\"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n\n# User key definitions\ndeclare -A USER_KEYS=(\n  # Fetch from public URL\n  [\"ubuntu\"]=\"raw:https://example.com/ssh-keys/ubuntu.authorized_keys\"\n  \n  # Fetch from private GitHub repository\n  [\"devuser\"]=\"api:https://api.github.com/repos/yourorg/ssh-keys/contents/keys/devuser.authorized_keys?ref=main\"\n  \n  # Fetch public keys from GitHub user\n  [\"alice\"]=\"ghuser:alice-github-username\"\n  [\"bob\"]=\"ghuser:bob-github-username\"\n)\n```\n\n## Usage\n\n### Command Line Options\n\n```bash\n./sync-ssh-keys.sh [OPTIONS]\n\nOPTIONS:\n  --self-update    Update the script to the latest version from GitHub\n  --help, -h       Show help message\n  --version, -v    Show version information\n```\n\n### Environment Variables\n\n- `GITHUB_TOKEN`: GitHub personal access token (overrides `CONF_GITHUB_TOKEN`)\n\n### Basic Usage\n\n```bash\n# Run synchronization\n./sync-ssh-keys.sh\n\n# Update script to latest version\n./sync-ssh-keys.sh --self-update\n\n# Show help\n./sync-ssh-keys.sh --help\n```\n\n## Examples\n\n### Team Management\n\nConfigure SSH access for a development team with mixed requirements:\n\n```bash\ndeclare -A USER_KEYS=(\n  # DevOps team with enterprise private keys\n  [\"devops-lead\"]=\"api:https://api.github.com/repos/company/ssh-keys/contents/team/devops-lead.keys?ref=main\"\n  [\"sre-admin\"]=\"api:https://api.github.com/repos/company/ssh-keys/contents/team/sre-admin.keys?ref=main\"\n  \n  # Developers using personal GitHub keys\n  [\"alice\"]=\"ghuser:alice-dev\"\n  [\"bob\"]=\"ghuser:bob-coder\"\n  [\"charlie\"]=\"ghuser:charlie-ops\"\n  \n  # Service accounts and automation\n  [\"ci-deploy\"]=\"raw:https://cdn.company.com/ci-keys/deploy-bot.keys\"\n  [\"backup-service\"]=\"raw:https://secure.company.com/service-keys/backup.authorized_keys\"\n)\n```\n\n### Staging vs Production\n\nDifferent configurations for different environments:\n\n```bash\n# staging.conf - More permissive for development\ndeclare -A USER_KEYS=(\n  [\"dev-alice\"]=\"ghuser:alice-personal\"\n  [\"dev-bob\"]=\"ghuser:bob-personal\"\n  [\"staging-deploy\"]=\"raw:https://staging-keys.company.com/deploy.keys\"\n)\n\n# production.conf - Strict enterprise keys only\ndeclare -A USER_KEYS=(\n  [\"prod-alice\"]=\"api:https://api.github.com/repos/company/prod-keys/contents/alice.keys?ref=main\"\n  [\"prod-deploy\"]=\"api:https://api.github.com/repos/company/prod-keys/contents/deploy.keys?ref=main\"\n)\n```\n\n### Multi-Region Deployment\n\nSync keys across multiple regions with different sources:\n\n```bash\ndeclare -A USER_KEYS=(\n  # Global admin access\n  [\"global-admin\"]=\"api:https://api.github.com/repos/company/global-keys/contents/admin.keys?ref=main\"\n  \n  # Region-specific access\n  [\"us-east-ops\"]=\"raw:https://us-east.company.com/ops-keys/authorized_keys\"\n  [\"eu-west-ops\"]=\"raw:https://eu-west.company.com/ops-keys/authorized_keys\"\n  [\"asia-ops\"]=\"raw:https://asia.company.com/ops-keys/authorized_keys\"\n)\n```\n\n### GitHub Token Setup\n\nFor accessing private repositories, you'll need a GitHub Personal Access Token:\n\n1. **Generate a token**:\n   - Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)\n   - Click \"Generate new token (classic)\"\n   - Select scopes: `repo` (for private repository access)\n   - Set an appropriate expiration date\n\n2. **Configure the token**:\n   ```bash\n   # Option 1: In configuration file\n   CONF_GITHUB_TOKEN=\"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n   \n   # Option 2: Environment variable\n   export GITHUB_TOKEN=\"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n   sudo -E ./sync-ssh-keys.sh\n   ```\n\n3. **Secure storage**:\n   ```bash\n   # Restrict configuration file permissions\n   chmod 600 users.conf\n   \n   # Or use a secrets management system\n   GITHUB_TOKEN=$(vault kv get -field=token secret/github/ssh-sync)\n   ```\n\n\u003e [!IMPORTANT]\n\u003e **Security Best Practice**: Use tokens with minimal required permissions and rotate them regularly. For organizations, consider using GitHub Apps instead of personal access tokens.\n\n## Automation\n\n### Production Deployment with Cron\n\nSet up automated synchronization for production environments:\n\n```bash\n# Edit root crontab\nsudo crontab -e\n\n# Sync every 15 minutes with logging\n*/15 * * * * /opt/ssh-key-sync/sync-ssh-keys.sh \u003e\u003e /var/log/ssh-key-sync.log 2\u003e\u00261\n\n# Daily summary report (optional)\n0 9 * * * grep \"$(date +%Y-%m-%d)\" /var/log/ssh-key-sync.log | mail -s \"SSH Key Sync Daily Report\" admin@company.com\n```\n\n### Modern Systemd Integration\n\nCreate a robust systemd service with automatic restart and monitoring:\n\n1. **Create the service** `/etc/systemd/system/ssh-key-sync.service`:\n   ```ini\n   [Unit]\n   Description=SSH Key Synchronization Service\n   Documentation=https://github.com/locus313/ssh-key-sync\n   After=network-online.target\n   Wants=network-online.target\n\n   [Service]\n   Type=oneshot\n   ExecStart=/opt/ssh-key-sync/sync-ssh-keys.sh\n   User=root\n   Group=root\n   StandardOutput=journal\n   StandardError=journal\n   \n   # Security settings\n   NoNewPrivileges=true\n   ProtectSystem=strict\n   ProtectHome=true\n   ReadWritePaths=/home /root\n   \n   [Install]\n   WantedBy=multi-user.target\n   ```\n\n2. **Create the timer** `/etc/systemd/system/ssh-key-sync.timer`:\n   ```ini\n   [Unit]\n   Description=Run SSH Key Sync every 10 minutes\n   Documentation=https://github.com/locus313/ssh-key-sync\n   Requires=ssh-key-sync.service\n\n   [Timer]\n   OnBootSec=5min\n   OnUnitActiveSec=10min\n   RandomizedDelaySec=2min\n   Persistent=true\n\n   [Install]\n   WantedBy=timers.target\n   ```\n\n3. **Deploy and monitor**:\n   ```bash\n   # Install and start\n   sudo systemctl daemon-reload\n   sudo systemctl enable ssh-key-sync.timer\n   sudo systemctl start ssh-key-sync.timer\n   \n   # Monitor status\n   sudo systemctl status ssh-key-sync.timer\n   sudo journalctl -u ssh-key-sync.service -f\n   ```\n\n### CI/CD Pipeline Integration\n\nIntegrate with popular CI/CD platforms for automated deployment:\n\n#### GitHub Actions\n```yaml\nname: Deploy and Sync SSH Keys\non:\n  push:\n    branches: [main]\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      \n      - name: Deploy application\n        run: ./deploy.sh\n        \n      - name: Sync SSH keys on target servers\n        run: |\n          # Download and run ssh-key-sync\n          curl -fsSL https://raw.githubusercontent.com/locus313/ssh-key-sync/main/sync-ssh-keys.sh | \\\n          ssh -o StrictHostKeyChecking=no deploy@${{ secrets.SERVER_HOST }} 'cat \u003e sync-ssh-keys.sh \u0026\u0026 chmod +x sync-ssh-keys.sh \u0026\u0026 sudo ./sync-ssh-keys.sh'\n        env:\n          GITHUB_TOKEN: ${{ secrets.SSH_SYNC_TOKEN }}\n```\n\n#### GitLab CI\n```yaml\nstages:\n  - deploy\n  - post-deploy\n\nsync-ssh-keys:\n  stage: post-deploy\n  script:\n    - apt-get update \u0026\u0026 apt-get install -y curl\n    - curl -fsSL https://raw.githubusercontent.com/locus313/ssh-key-sync/main/sync-ssh-keys.sh -o sync-ssh-keys.sh\n    - chmod +x sync-ssh-keys.sh\n    - ./sync-ssh-keys.sh\n  variables:\n    GITHUB_TOKEN: $CI_SSH_SYNC_TOKEN\n  only:\n    - main\n```\n\n#### Jenkins Pipeline\n```groovy\npipeline {\n    agent any\n    \n    environment {\n        GITHUB_TOKEN = credentials('ssh-sync-github-token')\n    }\n    \n    stages {\n        stage('Deploy') {\n            steps {\n                sh './deploy.sh'\n            }\n        }\n        \n        stage('Sync SSH Keys') {\n            steps {\n                sh '''\n                    curl -fsSL https://raw.githubusercontent.com/locus313/ssh-key-sync/main/sync-ssh-keys.sh -o sync-ssh-keys.sh\n                    chmod +x sync-ssh-keys.sh\n                    sudo ./sync-ssh-keys.sh\n                '''\n            }\n        }\n    }\n    \n    post {\n        always {\n            sh 'rm -f sync-ssh-keys.sh'\n        }\n    }\n}\n```\n\n## Troubleshooting\n\n### Common Issues and Solutions\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePermission denied errors\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Ensure script is executable\nchmod +x sync-ssh-keys.sh\n\n# Run with appropriate privileges (required for managing other users' SSH keys)\nsudo ./sync-ssh-keys.sh\n\n# Check file ownership and permissions\nls -la sync-ssh-keys.sh users.conf\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eGitHub API rate limits\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Use authenticated requests (increases rate limit from 60 to 5000 per hour)\nexport GITHUB_TOKEN=\"your_token_here\"\n\n# Monitor your rate limit\ncurl -H \"Authorization: token $GITHUB_TOKEN\" https://api.github.com/rate_limit\n\n# Consider reducing sync frequency for high-volume usage\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eNetwork connectivity issues\u003c/strong\u003e\u003c/summary\u003e\n\nThe script includes automatic retry logic (3 attempts by default), but you can troubleshoot:\n\n```bash\n# Test direct connectivity\ncurl -I https://github.com\ncurl -I https://api.github.com\n\n# Check DNS resolution\nnslookup github.com\n\n# Test with verbose curl output\ncurl -v https://github.com/username.keys\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eUser validation failures\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Check if user exists\nid username\n\n# Create user if needed\nsudo useradd -m username\n\n# Verify user home directory\ngetent passwd username\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eConfiguration syntax errors\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Validate Bash syntax\nbash -n users.conf\n\n# Check for common issues\n# - Missing quotes around array values\n# - Incorrect associative array syntax\n# - Typos in method names (raw, api, ghuser)\n```\n\u003c/details\u003e\n\n### Debug Mode\n\nEnable detailed debugging information:\n\n```bash\n# Run with bash debug mode\nbash -x sync-ssh-keys.sh\n\n# Or modify the script temporarily\n# Add 'set -x' at the top of sync-ssh-keys.sh\n```\n\n### Log Analysis\n\nUnderstanding log output:\n\n```bash\n# Successful execution logs\n2025-09-17 12:00:00: Starting SSH key synchronization (version 0.1.5)\n2025-09-17 12:00:01: Loading configuration...\n2025-09-17 12:00:01: Found 3 user(s) to process\n2025-09-17 12:00:02: Fetching key file for alice from https://github.com/alice.keys (method: ghuser)\n2025-09-17 12:00:03: Updated authorized_keys for user 'alice' at /home/alice/.ssh/authorized_keys\n2025-09-17 12:00:03: Successfully processed user 'alice'\n2025-09-17 12:00:04: Synchronization complete. Processed: 3, Failed: 0\n\n# Error patterns to watch for\nERROR: User 'nonexistent' does not exist. Skipping.\nERROR: GITHUB_TOKEN is required for API access\nERROR: Failed to fetch key file for user 'alice' from https://invalid-url after multiple attempts\nWARNING: No changes detected in authorized_keys for user 'bob'\n```\n\n## Testing\n\nThe project includes comprehensive testing infrastructure to ensure reliability and prevent regressions:\n\n### Automated Testing Pipeline\n\n[![CI Status](https://img.shields.io/github/actions/workflow/status/locus313/ssh-key-sync/ci.yml?style=flat-square\u0026label=CI)](https://github.com/locus313/ssh-key-sync/actions)\n\nThe project uses a **centralized CI workflow** that orchestrates all testing and validation:\n\n- **Lint Check** - ShellCheck static analysis for code quality and best practices\n- **Version Check** - Ensures version bumps in pull requests for proper release management\n- **Integration Tests** - Real user creation, SSH key synchronization, and error handling validation\n- **Multi-Environment Testing** - Validation across different Linux distributions\n- **Security Focus** - Proper permissions, file handling, and authentication validation\n\n\u003e [!NOTE]\n\u003e **Workflow Architecture**: The CI workflow calls individual test workflows (`lint.yml`, `test.yml`, `check-version.yml`) as reusable workflows, preventing duplicate runs while maintaining organized test separation.\n\n### Running Tests Locally\n\n```bash\n# Quick validation suite\n./test.sh\n\n# Manual syntax validation\nbash -n sync-ssh-keys.sh\n\n# With ShellCheck (recommended)\nshellcheck sync-ssh-keys.sh\n\n# Test with dry-run mode (if implemented)\n./sync-ssh-keys.sh --dry-run\n```\n\n### Test Coverage\n\nThe test suite validates:\n- ✅ Configuration file parsing and validation\n- ✅ User existence and permission checks  \n- ✅ Network connectivity and retry logic\n- ✅ File operations and atomic updates\n- ✅ Error handling and edge cases\n- ✅ GitHub API integration\n- ✅ Security permissions and ownership\n\n### Development Testing\n\nFor contributors and advanced users:\n\n```bash\n# Create isolated test environment\ndocker run -it --rm ubuntu:22.04 bash\n\n# Install dependencies and test\napt update \u0026\u0026 apt install -y curl bash\ncurl -fsSL https://raw.githubusercontent.com/locus313/ssh-key-sync/main/test.sh | bash\n```\n\n\u003e [!NOTE]\n\u003e For detailed testing procedures and guidelines, see [TESTING.md](TESTING.md).\n\n## Security Considerations\n\n\u003e [!IMPORTANT]\n\u003e **Production Security Checklist**\n\u003e - [ ] Store GitHub tokens securely and rotate them regularly (every 90 days recommended)\n\u003e - [ ] Use least-privilege tokens with only required scopes (`repo` for private repos)\n\u003e - [ ] Monitor logs for failed authentication attempts and unusual activity\n\u003e - [ ] Validate SSH key sources and ownership before adding to configuration\n\u003e - [ ] Use private repositories for sensitive key storage, never public ones\n\u003e - [ ] Implement proper backup and recovery procedures for SSH key configuration\n\u003e - [ ] Regular audit of user access and key validity\n\n### Token Security\n\n```bash\n# Use environment variables instead of hardcoding tokens\nexport GITHUB_TOKEN=\"$(vault kv get -field=token secret/github/ssh-sync)\"\n\n# Restrict configuration file permissions\nchmod 600 users.conf\nchown root:root users.conf\n\n# Consider using GitHub Apps for organization-wide deployments\n# They provide better security and audit trails than personal access tokens\n```\n\n### Network Security\n\n```bash\n# Validate SSL certificates (default behavior)\n# The script uses curl with strict SSL validation\n\n# For air-gapped environments, consider using local mirrors\ndeclare -A USER_KEYS=(\n  [\"user\"]=\"raw:https://internal-mirror.company.com/keys/user.authorized_keys\"\n)\n\n# Monitor network traffic if required\ntcpdump -i any host github.com\n```\n\n### File System Security\n\nThe script automatically implements security best practices:\n\n- **SSH Directory**: `700` permissions (owner access only)\n- **Authorized Keys**: `600` permissions (owner read/write only)  \n- **Proper Ownership**: All files owned by the target user\n- **Atomic Operations**: Temporary files with secure cleanup\n- **Input Validation**: Validates all user inputs and file paths\n\n### Audit and Compliance\n\n```bash\n# Enable comprehensive logging for compliance\nsudo ./sync-ssh-keys.sh 2\u003e\u00261 | tee -a /var/log/ssh-key-sync-audit.log\n\n# Log rotation for long-term storage\ncat \u003e /etc/logrotate.d/ssh-key-sync \u003c\u003c EOF\n/var/log/ssh-key-sync*.log {\n    daily\n    rotate 365\n    compress\n    delaycompress\n    missingok\n    notifempty\n    create 640 root adm\n}\nEOF\n```\n\n## FAQ\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCan I use this script with GitLab, Bitbucket, or other Git providers?\u003c/strong\u003e\u003c/summary\u003e\n\nCurrently, the script has built-in support for GitHub's API and public key endpoints. For other providers:\n\n- **GitLab**: Use the `raw` method with GitLab's raw file URLs\n- **Bitbucket**: Use the `raw` method with Bitbucket's raw file URLs  \n- **Azure DevOps**: Use the `raw` method with Azure DevOps file URLs\n- **Custom Git servers**: Use the `raw` method with direct HTTPS URLs\n\nExample:\n```bash\n[\"user\"]=\"raw:https://gitlab.com/username/ssh-keys/-/raw/main/user.keys\"\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eWhat happens if a user doesn't exist on the system?\u003c/strong\u003e\u003c/summary\u003e\n\nThe script validates user existence before processing and will:\n1. Log a warning message\n2. Skip that user entirely  \n3. Continue processing other users\n4. Report the failure in the final summary\n\nThis ensures the script doesn't fail completely due to one missing user.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eHow often should I run the synchronization?\u003c/strong\u003e\u003c/summary\u003e\n\nRecommended frequencies based on environment:\n- **Development**: Every 15-30 minutes for rapid iteration\n- **Staging**: Every 1-2 hours for testing stability\n- **Production**: Every 4-6 hours for security balance\n- **High-security environments**: Every 1 hour with audit logging\n\nConsider your team's SSH key rotation frequency and security requirements.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCan I customize the retry logic and timeouts?\u003c/strong\u003e\u003c/summary\u003e\n\nYes, the script uses configurable constants that you can modify:\n\n```bash\n# Edit these variables in sync-ssh-keys.sh\nreadonly DEFAULT_RETRIES=3\nreadonly DEFAULT_RETRY_DELAY=2\n\n# Or pass them as parameters (if you modify the script)\nfetch_key_file \"$method\" \"$target\" \"$temp_file\" 5 3  # 5 retries, 3 second delay\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eIs there a dry-run mode to test configuration?\u003c/strong\u003e\u003c/summary\u003e\n\nWhile not currently implemented, you can safely test by:\n\n1. **Configuration validation**: `bash -n users.conf`\n2. **Syntax check**: `bash -n sync-ssh-keys.sh`  \n3. **Test environment**: Run on a test system with test users\n4. **Verbose logging**: Use `bash -x sync-ssh-keys.sh` for detailed output\n\nA dry-run mode is planned for future releases.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eHow do I handle SSH key rotation?\u003c/strong\u003e\u003c/summary\u003e\n\nThe script automatically handles key rotation:\n\n1. **Update the source** (GitHub keys, file URLs, etc.)\n2. **Run the sync** - the script detects changes automatically\n3. **Verify the update** - check the logs for confirmation\n\nThe script only updates files when content actually changes, making it safe to run frequently.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCan I exclude certain keys or add filtering?\u003c/strong\u003e\u003c/summary\u003e\n\nCurrently, the script syncs all keys from the configured source. For filtering:\n\n1. **Source-level filtering**: Maintain filtered key files at the source\n2. **Multiple sources**: Create separate endpoints for different key sets\n3. **Custom scripts**: Pipe through additional filtering if needed\n\nAdvanced filtering features may be added in future versions.\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocus313%2Fssh-key-sync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocus313%2Fssh-key-sync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocus313%2Fssh-key-sync/lists"}