Skip to content

mitre/train-juniper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Train Juniper Plugin

A production-ready Train plugin that provides SSH connectivity to Juniper Networks devices running JunOS for InSpec compliance testing and infrastructure inspection.

!!! info "Quick Start" Install the plugin: inspec plugin install train-juniper and start testing your Juniper infrastructure immediately.

Features :material-star:

The plugin supports:

  • :material-ssh: SSH Authentication - Secure connections with password or key-based auth
  • :material-router-network: JunOS Platform Detection - Automatic version parsing and platform registration
  • :material-console: Command Execution - CLI command execution with Juniper-specific prompt handling
  • :material-network: Proxy/Bastion Support - Enterprise network connectivity through jump hosts
  • :material-file-document: Configuration Inspection - Pseudo-file operations for configuration access
  • :material-test-tube: Mock Mode - Complete testing support without requiring real hardware
  • :material-speedometer: Performance Optimized - Efficient platform detection with result caching

Installation :material-download:

!!! warning "Prerequisites" You will need InSpec v4.0 or later.

Production Installation (from RubyGems)

# Search for train plugins
$ inspec plugin search train-

# Install train-juniper (once published)
$ inspec plugin install train-juniper

# Verify installation
$ inspec plugin list

Development Installation (local testing)

# Clone the repository
$ git clone https://github.com/mitre/train-juniper.git
$ cd train-juniper

# Install dependencies and run tests
$ bundle install
$ bundle exec rake test

# Build and install local gem
$ gem build train-juniper.gemspec
$ inspec plugin install ./train-juniper-0.1.0.gem

# Verify plugin is loaded
$ inspec plugin list

Usage

Basic Connection

# Detect platform
$ inspec detect -t juniper://[email protected] --password yourpassword

== Platform Details
Name:      juniper
Families:  bsd
Release:   21.4R3-S1.6
Arch:      x86_64

# Interactive shell
$ inspec shell -t juniper://[email protected] --password yourpassword
inspec> command('show version').stdout
=> "Hostname: srx-fw\nModel: SRX340\nJunos: 21.4R3-S1.6\n..."

With Bastion Host (Jump Host)

# Simplified: Same username/password for bastion and device (most common)
$ inspec shell -t juniper://[email protected] --password yourpassword \
    --bastion-host jump.example.com

# Different credentials for bastion and device
$ inspec shell -t juniper://[email protected] --password device_password \
    --bastion-host jump.example.com --bastion-user netadmin \
    --bastion-password jump_password

# With custom port
$ inspec shell -t juniper://[email protected] --password yourpassword \
    --bastion-host jump.example.com --bastion-port 2222

# Using environment variables (recommended for automation)
export JUNIPER_BASTION_HOST=jump.example.com
export JUNIPER_PASSWORD=shared_password  # Used for both bastion and device
$ inspec shell -t juniper://[email protected]

# Different passwords via environment
export JUNIPER_BASTION_HOST=jump.example.com
export JUNIPER_BASTION_USER=netadmin  
export JUNIPER_BASTION_PASSWORD=jump_password
export JUNIPER_PASSWORD=device_password
$ inspec shell -t juniper://[email protected]

With Custom Proxy Command

# Using SSH ProxyCommand syntax  
$ inspec shell -t "juniper://[email protected]?proxy_command=ssh%20jump.host%20-W%20%h:%p"

# Complex corporate network scenario
$ inspec detect -t "juniper://[email protected]?bastion_host=jump.dmz.corp&bastion_user=svc_inspec"

Environment Variables (Auto-Detection)

The plugin automatically detects and uses standard environment variables, eliminating the need to pass connection flags:

# Basic connection with auto-detection
export JUNIPER_HOST=192.168.1.1
export JUNIPER_USER=admin  
export JUNIPER_PASSWORD=yourpassword
inspec detect -t juniper://  # No flags needed!

# With bastion host auto-detection
export JUNIPER_HOST=internal.device.corp
export JUNIPER_USER=netadmin
export JUNIPER_PASSWORD=devicepass
export JUNIPER_BASTION_HOST=jump.corp.com
export JUNIPER_BASTION_USER=admin
export JUNIPER_BASTION_PASSWORD=bastionpass
inspec detect -t juniper://  # Automatically uses bastion!

# Using .env file (recommended for development)
# Create .env file with your credentials:
source .env
inspec detect -t juniper://  # Reads from .env automatically

Configuration Options

Option Priority

The plugin uses the following priority order for configuration values:

  1. Command-line flags (highest priority) - e.g., --bastion-user
  2. Environment variables - e.g., JUNIPER_BASTION_USER
  3. Defaults/Fallbacks (lowest priority) - e.g., bastion_user falls back to main user

This allows maximum flexibility while providing sensible defaults for common scenarios.

Connection Options

Option Description Default Environment Variable
host Juniper device hostname/IP - JUNIPER_HOST
user SSH username - JUNIPER_USER
password SSH password - JUNIPER_PASSWORD
port SSH port 22 JUNIPER_PORT
timeout Connection timeout (seconds) 30 JUNIPER_TIMEOUT
keepalive SSH keepalive enabled true -
keepalive_interval SSH keepalive interval (seconds) 60 -

Proxy/Bastion Options

Option Description Default Environment Variable
bastion_host SSH bastion/jump host - JUNIPER_BASTION_HOST
bastion_user SSH bastion username Falls back to main user JUNIPER_BASTION_USER
bastion_port SSH bastion port 22 JUNIPER_BASTION_PORT
bastion_password Password for bastion authentication - JUNIPER_BASTION_PASSWORD
proxy_command Custom SSH ProxyCommand - JUNIPER_PROXY_COMMAND
key_files SSH private key files - -
keys_only Use only specified keys false -

!!! note "Important Configuration Notes" - Cannot specify both bastion_host and proxy_command simultaneously - If bastion_user not provided, falls back to using main user for bastion authentication - If bastion_password not provided, falls back to using main password for bastion authentication - Supports automated password authentication via SSH_ASKPASS mechanism

InSpec Configuration File

Create ~/.inspec/config.json:

{
  "credentials": {
    "juniper-lab": {
      "target": "juniper://[email protected]",
      "password": "yourpassword",
      "insecure": true
    }
  }
}

Then use: inspec detect --config=juniper-lab

Proxy Connection Patterns

The train-juniper plugin supports Train-standard proxy/bastion connections for enterprise environments where Juniper devices are behind jump hosts or in isolated network segments.

Authentication Patterns

Important: Train does not have a separate --bastion-password option. Here are the standard authentication patterns:

🔐 Same Credentials (Most Common)

Use the same --password for both bastion host and Juniper device:

# Same username/password for jump host and device
inspec detect -t "juniper://[email protected]?bastion_host=jump.corp.com&bastion_user=admin" --password "shared_password"

# With environment variables
export JUNIPER_PASSWORD="shared_password"
inspec shell -t "juniper://[email protected]?bastion_host=jump.corp.com&bastion_user=admin"

🔑 SSH Key Authentication (Recommended)

Use SSH keys for both connections:

# SSH keys for both bastion and device
inspec detect -t "juniper://[email protected]?bastion_host=jump.corp.com&bastion_user=admin" -i ~/.ssh/id_rsa

# With multiple keys
inspec shell -t "juniper://[email protected]?bastion_host=jump.corp.com" --key-files ~/.ssh/bastion_key ~/.ssh/device_key

🔗 Different Credentials (Advanced)

Use SSH ProxyCommand when bastion and device require different authentication:

# Bastion uses one password, device uses another (embed bastion auth in proxy command)
inspec detect -t "juniper://[email protected]?proxy_command=sshpass%20-p%20bastionpass%20ssh%[email protected]%20-W%20%h:%p" --password "device_password"

# Bastion uses SSH key, device uses password
inspec shell -t "juniper://[email protected]?proxy_command=ssh%20-i%20~/.ssh/bastion_key%[email protected]%20-W%20%h:%p" --password "device_password"

Bastion Host Scenarios

# Corporate network with dedicated jump host
inspec exec profile -t "juniper://[email protected]?bastion_host=jump.corp.com&bastion_user=netadmin" --password "shared_password"

# Cloud environment with bastion instance  
inspec exec profile -t "juniper://[email protected]?bastion_host=bastion.aws.company.com&bastion_port=2222" --key-files ~/.ssh/aws_key

# DMZ access pattern
inspec detect -t "juniper://[email protected]?bastion_host=jump.dmz.corp&bastion_user=svc_account" --password "corporate_password"

Custom Proxy Commands

# SSH ProxyCommand for complex routing
inspec shell -t "juniper://admin@device?proxy_command=ssh%20-o%20StrictHostKeyChecking=no%20jump%20nc%20%h%20%p"

# Multi-hop proxy (SSH chain)
inspec exec profile -t "juniper://admin@target?proxy_command=ssh%20-J%20first-jump,second-jump%20-W%20%h:%p"

SSH Key Authentication with Proxy

# In Ruby code or configuration
Train.create('juniper', {
  host: 'secure.device.corp',
  user: 'admin',
  bastion_host: 'jump.corp.com',
  bastion_user: 'automation',
  key_files: ['/path/to/private/key'],
  keys_only: true
})

Common Authentication Issues

❌ Error: "No bastion password specified"

Solution: Train doesn't have --bastion-password. Use one of these patterns:

# Same password for both (most common)
inspec detect -t "juniper://user@device?bastion_host=jump" --password "shared_pass"

# SSH keys (recommended)  
inspec detect -t "juniper://user@device?bastion_host=jump" --key-files ~/.ssh/id_rsa

# Different passwords (use proxy command)
inspec detect -t "juniper://user@device?proxy_command=sshpass%20-p%20jumppass%20ssh%20jumpuser@jump%20-W%20%h:%p" --password "device_pass"

❌ Error: "Authentication failed"

Solutions:

# Verify bastion connection first
ssh [email protected]

# Test direct device connection (if accessible)
ssh [email protected]

# Use verbose SSH for debugging
inspec detect -t "juniper://user@device?bastion_host=jump&proxy_command=ssh%20-v%20jump%20-W%20%h:%p" --password "pass"

# Use InSpec debug mode for detailed logging
inspec detect -t "juniper://user@device?bastion_host=jump" --password "pass" -l debug

❌ Error: "Connection timeout"

Solutions:

# Increase timeouts
inspec detect -t "juniper://user@device?bastion_host=jump&connection_timeout=60" --password "pass"

# Check network connectivity
ping device.internal  # From bastion host
telnet device.internal 22  # Test SSH port

Mock Mode (Testing Without Hardware)

The train-juniper plugin includes a comprehensive mock mode for testing profiles without requiring physical Juniper hardware:

# Use mock mode with InSpec detect
inspec detect -t "juniper://admin@mock-device?mock=true"

# Output shows mocked JunOS platform:
# Name:      juniper
# Families:  bsd
# Release:   12.1X47-D15.4

For programmatic usage in tests:

require 'train'
connection = Train.create('juniper', 
  host: 'test-device',
  user: 'admin',
  mock: true
)

# Mock mode returns predefined responses
result = connection.run_command('show version')
# => Returns mock JunOS version output

Mock mode provides:

  • ✅ Realistic JunOS command outputs
  • ✅ Platform detection (JunOS 12.1X47-D15.4)
  • ✅ Error simulation for negative testing
  • ✅ Fast execution for CI/CD pipelines

Development

Requirements

  • Ruby 3.1+
  • Bundler
  • InSpec 4.0+ (for testing)

Setup

git clone https://github.com/mitre/train-juniper.git
cd train-juniper
bundle install

Testing

# Run all tests
bundle exec rake test

# Run individual test suites  
bundle exec ruby test/unit/connection_test.rb
bundle exec ruby test/functional/juniper_test.rb

# Lint code
bundle exec rubocop

Architecture

This plugin implements the Train Plugin V1 API with:

  • Transport (lib/train-juniper/transport.rb) - Plugin registration and factory
  • Connection (lib/train-juniper/connection.rb) - SSH connectivity and command execution
  • Platform (lib/train-juniper/platform.rb) - JunOS platform detection
  • Version (lib/train-juniper/version.rb) - Plugin version management

Platform Support

This gem supports a wide range of platforms to ensure maximum compatibility:

Platform Description Use Case
ruby Platform-independent Pure Ruby installations
x86_64-linux Standard Linux Most Linux servers and CI/CD
aarch64-linux ARM64 Linux AWS Graviton, Raspberry Pi
x86_64-linux-musl Alpine Linux Docker containers
x86_64-darwin Intel macOS Older Mac workstations
arm64-darwin-* Apple Silicon macOS Modern Mac workstations
x64-mingw-ucrt Windows (UCRT) Windows 10/11 with modern Ruby (bastion setup)
x86_64-freebsd FreeBSD Network appliances (JunOS heritage)
x86_64-solaris Solaris/illumos Enterprise environments

!!! note "Platform Compatibility" This comprehensive platform support ensures the plugin works wherever InSpec runs, from developer workstations to CI/CD pipelines to production jump hosts. The FreeBSD support is particularly relevant given that JunOS is based on FreeBSD.

Documentation

Plugin Development Resources

  • Train Plugin Development Guide - Comprehensive tutorial for Train plugin development
  • How This Plugin Was Built - See modules 20-22 in the development guide for our research methodology, implementation approach, and containerlab testing environment

Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Run bundle exec rake test to ensure tests pass
  5. Submit a pull request

Please see our Contributing Guide for more details.

Support and Contact

General Support

For questions, feature requests, or general support:

Security Issues

For security issues or vulnerabilities:

Acknowledgments

This project was inspired by and references several excellent community Train plugins:

  • train-rest by Thomas Heinen (Prospectra) - REST API transport patterns
  • train-awsssm by Thomas Heinen (Prospectra) - AWS Systems Manager transport
  • train-pwsh by MITRE SAF Team - PowerShell/Windows automation transport
  • train-k8s-container by InSpec Team - Kubernetes container platform detection
  • train-local-rot13 by InSpec Team - Official plugin development example

Special thanks to the Train and InSpec communities for their excellent documentation and plugin examples.

License

Licensed under the Apache-2.0 license, except as noted below.

See LICENSE for full details.

Notice

This software was produced for the U.S. Government under contract and is subject to Federal Acquisition Regulation Clause 52.227-14.

See NOTICE for full details.

© 2025 The MITRE Corporation.

About

Train transport for Juniper Networks JunOS devices - enables InSpec compliance testing and infrastructure inspection

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published