Skip to content

Commit

Permalink
Merge pull request #3545 from ktbyers/develop
Browse files Browse the repository at this point in the history
Netmiko Version 4.5.0
  • Loading branch information
ktbyers authored Dec 9, 2024
2 parents 07e0ac1 + 7ce4f41 commit d762390
Show file tree
Hide file tree
Showing 264 changed files with 11,118 additions and 39,993 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main_testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
shell: bash
strategy:
matrix:
python-version: [ '3.8', '3.9', '3.10', '3.11', "3.12", "3.13.0-beta.2" ]
python-version: [ '3.9', '3.10', '3.11', "3.12", "3.13" ]
platform: [ubuntu-24.04, windows-2022]

runs-on: ${{ matrix.platform }}
Expand Down Expand Up @@ -96,7 +96,7 @@ jobs:
shell: bash
strategy:
matrix:
python-version: [ '3.8', '3.9', '3.10', '3.11' ]
python-version: [ '3.9', '3.10', '3.11' ]
platform: [macos-13]

runs-on: ${{ matrix.platform }}
Expand Down
148 changes: 148 additions & 0 deletions ENCRYPTION_HANDLING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Netmiko Encryption Handling

This document describes the encryption mechanisms available in Netmiko for handling sensitive data in configuration files. These mechanisms are generally intended for use with `~/.netmiko.yml` and Netmiko Tools.

## Overview

Netmiko provides built-in encryption capabilities to secure sensitive data (like passwords) in your Netmiko Tools YAML configuration files. The encryption system is flexible and supports multiple encryption types.

## Configuration

### Basic Setup

Encryption is configured in the `~/.netmiko.yml` file using the `__meta__` field:

```yaml
__meta__:
encryption: true
encryption_type: fernet # or aes128
```
The two supported encryption types are:
- `fernet` (recommended)
- `aes128`

### Encryption Key

The encryption key is read from the environment variable `NETMIKO_TOOLS_KEY`. This should be a secure, randomly-generated key appropriate for the chosen encryption type.

```bash
# Example of setting the encryption key
export NETMIKO_TOOLS_KEY="your-secure-key-here"
```

## Using Encryption

### Encrypted Values in YAML

When encryption is enabled, Netmiko looks for fields that start with `__encrypt__`. For example:

```yaml
arista1:
device_type: arista_eos
host: arista1.domain.com
username: pyclass
password: >
__encrypt__ifcs7SWOUER4m1K3ZEZYlw==:Z0FBQUFBQm5CQ9lrdV9BVS0xOWxYelF1Yml
zV3hBcnF4am1SWjRYNnVSRGdBb1FPVmJ2Q2EzX1RjTWxYMVVMdlBZSXVqYWVqUVNASXNRO
FBpR1MxRTkxN2J0NWxVeZNKT0E9PQ==
```

### Encryption Functions

#### Encrypting Values

To encrypt a value, use the `encrypt_value` function:

```python
def encrypt_value(value: str, key: bytes, encryption_type: str) -> str:
"""
Encrypt a value using the specified encryption type.
Args:
value: The string to encrypt
key: Encryption key as bytes
encryption_type: Either 'fernet' or 'aes128'
Returns:
Encrypted string with '__encrypt__' prefix
"""
```

#### Decrypting Values

To decrypt a value, use the `decrypt_value` function:

```python
def decrypt_value(encrypted_value: str, key: bytes, encryption_type: str) -> str:
"""
Decrypt a value using the specified encryption type.
Args:
encrypted_value: The encrypted string (including '__encrypt__' prefix)
key: Encryption key as bytes
encryption_type: Either 'fernet' or 'aes128'
Returns:
Decrypted string
"""
```

#### Getting the Encryption Key

To retrieve the encryption key from the environment:

```python
def get_encryption_key() -> bytes:
"""
Retrieve the encryption key from NETMIKO_TOOLS_KEY environment variable.
Returns:
Encryption key as bytes
"""
```

## Example Usage

Here's a complete example of how to use encryption in your code:

```python
from netmiko.encryption_handling import encrypt_value, get_encryption_key
from netmiko.encryption_handling import decrypt_value
# Get the encryption key from environment
key = get_encryption_key()
# Encrypt a password
password = "my_secure_password"
encrypted_password = encrypt_value(password, key, "fernet")
# The encrypted password can now be stored in your YAML file
# It will automatically be decrypted when Netmiko Tools reads the
# file (assuming you have properly set the '__meta__' fields
```

Alternatively, you can decrypt the value by calling

```python
clear_value = decrypt_value(encrypted_value, key, encryption_type="fernet)
```

Or you can create a simple function to decrypt all of the fields in the YAML
file dynamically (by looking for any fields that start with `__encrypt__`).

Netmiko's 'encryption_handling.py' implements this using the 'decrypt_config'
function, but this function is a specific to Netmiko Tools' .netmiko.yml format
(i.e. it will need modified if you want to use it in a more generic context).

## Implementation Notes

1. Encryption is processed transparently when Netmiko Tools reads the YAML file
2. Only fields prefixed with `__encrypt__` are processed for decryption
3. The encryption type is determined by the `__meta__` section

## Security Considerations

1. Store the `NETMIKO_TOOLS_KEY` securely and never commit it to version control
2. Fernet encryption is recommended over AES128 as it includes additional security features
3. Encrypted values in YAML files should still be treated as sensitive data
4 changes: 4 additions & 0 deletions PLATFORMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@

- A10
- Accedian
- Alaxala AX2600S and AX3600S
- Allied Telesis AlliedWare Plus
- Aruba OS (Wireless Controllers/WAPs)
- Aruba AOS-CX
- Brocade Fabric OS
- C-DOT CROS
- Ciena SAOS
- Citrix Netscaler
- Cisco APIC (Linux)
- Cisco Telepresence
- Cisco Viptela
- Check Point GAiA
Expand All @@ -96,6 +98,7 @@
- F5 TMSH
- F5 Linux
- Fortinet
- Garderos GRS
- MRV Communications OptiSwitch
- MRV LX
- Nokia/Alcatel SR-OS
Expand All @@ -106,6 +109,7 @@
- Sophos SFOS
- Ubiquiti Unifi Switch
- Versa Networks FlexVNF
- Vertiv MPH Power Distribution Units
- Watchguard Firebox
- Zyxel NOS
- 6WIND TurboRouter
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Netmiko aims to accomplish both of these operations and to do it across a very b

## Installation

To install netmiko, simply us pip:
To install netmiko, simply use pip:

```
$ pip install netmiko
Expand Down
80 changes: 15 additions & 65 deletions docs/netmiko/a10/a10_ssh.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="generator" content="pdoc 0.10.0" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<meta name="generator" content="pdoc3 0.11.1">
<title>netmiko.a10.a10_ssh API documentation</title>
<meta name="description" content="A10 support." />
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
<meta name="description" content="A10 support.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
<script>window.addEventListener('DOMContentLoaded', () => {
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
hljs.highlightAll();
})</script>
</head>
<body>
<main>
Expand All @@ -23,34 +26,6 @@ <h1 class="title">Module <code>netmiko.a10.a10_ssh</code></h1>
</header>
<section id="section-intro">
<p>A10 support.</p>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">&#34;&#34;&#34;A10 support.&#34;&#34;&#34;

from netmiko.cisco_base_connection import CiscoSSHConnection


class A10SSH(CiscoSSHConnection):
&#34;&#34;&#34;A10 support.&#34;&#34;&#34;

def session_preparation(self) -&gt; None:
&#34;&#34;&#34;A10 requires to be enable mode to disable paging.&#34;&#34;&#34;
self._test_channel_read(pattern=r&#34;[&gt;#]&#34;)
self.set_base_prompt()
self.enable()

# terminal width ill not do anything without A10 specific command
# self.set_terminal_width()
self.disable_paging(command=&#34;terminal length 0&#34;)

def save_config(
self, cmd: str = &#34;&#34;, confirm: bool = False, confirm_response: str = &#34;&#34;
) -&gt; str:
&#34;&#34;&#34;Not Implemented&#34;&#34;&#34;
raise NotImplementedError</code></pre>
</details>
</section>
<section>
</section>
Expand Down Expand Up @@ -222,36 +197,12 @@ <h3>Methods</h3>
</code></dt>
<dd>
<div class="desc"><p>Not Implemented</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def save_config(
self, cmd: str = &#34;&#34;, confirm: bool = False, confirm_response: str = &#34;&#34;
) -&gt; str:
&#34;&#34;&#34;Not Implemented&#34;&#34;&#34;
raise NotImplementedError</code></pre>
</details>
</dd>
<dt id="netmiko.a10.a10_ssh.A10SSH.session_preparation"><code class="name flex">
<span>def <span class="ident">session_preparation</span></span>(<span>self) ‑> None</span>
</code></dt>
<dd>
<div class="desc"><p>A10 requires to be enable mode to disable paging.</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def session_preparation(self) -&gt; None:
&#34;&#34;&#34;A10 requires to be enable mode to disable paging.&#34;&#34;&#34;
self._test_channel_read(pattern=r&#34;[&gt;#]&#34;)
self.set_base_prompt()
self.enable()

# terminal width ill not do anything without A10 specific command
# self.set_terminal_width()
self.disable_paging(command=&#34;terminal length 0&#34;)</code></pre>
</details>
</dd>
</dl>
<h3>Inherited members</h3>
Expand Down Expand Up @@ -305,7 +256,6 @@ <h3>Inherited members</h3>
</section>
</article>
<nav id="sidebar">
<h1>Index</h1>
<div class="toc">
<ul></ul>
</div>
Expand All @@ -330,7 +280,7 @@ <h4><code><a title="netmiko.a10.a10_ssh.A10SSH" href="#netmiko.a10.a10_ssh.A10SS
</nav>
</main>
<footer id="footer">
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.1</a>.</p>
</footer>
</body>
</html>
</html>
Loading

0 comments on commit d762390

Please sign in to comment.