initial
No files matched your search
@@ -0,0 +1,15 @@
|
||||
({
|
||||
katexConfig: {
|
||||
"macros": {}
|
||||
},
|
||||
|
||||
mathjaxConfig: {
|
||||
"tex": {},
|
||||
"options": {},
|
||||
"loader": {}
|
||||
},
|
||||
|
||||
mermaidConfig: {
|
||||
"startOnLoad": false
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
<!-- The content below will be included at the end of the <head> element. -->
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// your code here
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
({
|
||||
// Please visit the URL below for more information:
|
||||
// https://shd101wyy.github.io/markdown-preview-enhanced/#/extend-parser
|
||||
|
||||
onWillParseMarkdown: async function(markdown) {
|
||||
return markdown;
|
||||
},
|
||||
|
||||
onDidParseMarkdown: async function(html) {
|
||||
return html;
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
/* Please visit the URL below for more information: */
|
||||
/* https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */
|
||||
|
||||
.markdown-preview.markdown-preview {
|
||||
// modify your style here
|
||||
// eg: background-color: blue;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# how to build
|
||||
```docker run --rm -v $PWD:/home/marp/app/ -e LANG=$LANG marpteam/marp-cli presentation.md```
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 733 KiB |
|
After Width: | Height: | Size: 521 KiB |
|
After Width: | Height: | Size: 394 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 387 KiB |
|
After Width: | Height: | Size: 373 KiB |
|
After Width: | Height: | Size: 513 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
@@ -0,0 +1,78 @@
|
||||
---
|
||||
theme: jobs
|
||||
_class: lead
|
||||
size: 16:9
|
||||
paginate: true
|
||||
#footer: "Felix EVPN Demo"
|
||||
marp: true
|
||||
backgroundColor: #fff
|
||||
backgroundImage: url('https://marp.app/assets/hero-background.svg')
|
||||
---
|
||||
<!-- _backgroundImage: url('https://marp.app/assets/hero-background.svg') -->
|
||||
# **EVPN Demo**
|
||||
|
||||
2024-07-17 Munich
|
||||
Felix Schüren
|
||||
|
||||
---
|
||||

|
||||
## lab diagram reference
|
||||
<span style="color: darkgrey; font-size: 0.4em">Lo0 numbering from left to right, starting at ```.1```</span>
|
||||
<span style="color: darkgrey; font-size: 0.4em">management via hostname, prefix is ```clab-f3-```</span>
|
||||
<style scoped>
|
||||
ul {
|
||||
font-size: smaller;
|
||||
}
|
||||
</style>
|
||||
- Spines
|
||||
- 10.0.255/24
|
||||
- Leaves
|
||||
- 10.0.254/24
|
||||
|
||||
---
|
||||
<!-- _backgroundColor: white -->
|
||||
<!-- _backgroundImage: "" -->
|
||||
<style scoped>
|
||||
ul {
|
||||
font-size: smaller;
|
||||
}
|
||||
</style>
|
||||

|
||||
- basic Spine/Leaf architecture
|
||||
- border/service leaf
|
||||
- keep spine config as simple as possible
|
||||
- help humans
|
||||
- eBGP underlay
|
||||
- I come from a service provider background, BGP is second nature
|
||||
- bgp unnumbered instead of /31
|
||||
- easier debugging of BGP sessions etc as you can see the Interface name in BGP :)
|
||||
- no IPAM for underlay transfer links
|
||||
<!-- Only scenario where it might make sense to use IS-IS or OSPF in the underlay is if there are different teams responsible to run underlay/core transport vs overlay/services/end customer needs-->
|
||||
---
|
||||

|
||||

|
||||
|
||||
---
|
||||

|
||||

|
||||
|
||||
---
|
||||
MLAG: querlink noetig, aber weniger EVPN-Routen, vendor-spezifisch
|
||||
EVPN-Multihoming: kein querlink, aber mehr Routen, ...
|
||||
|
||||
underlay/overlay via AVD fertigmachen
|
||||
|
||||
service deployment via ansible oder so (VLANs, VNIs, ...)
|
||||
|
||||
v4-less underlay? 5549 nexthop rewriting mit interface-peering, damit baut sich ein neues leaf quasi umsonst
|
||||
|
||||
weitere leaf(s) dazubauen im Betrieb
|
||||
|
||||
eAPI, eAPI-Docs raussuchen
|
||||
|
||||
show commands rund um evpn (welche mac wo, aktueller Zustand, etc)
|
||||
|
||||
|
||||
tmux auf einem arista-switch installieren und casual anmoderieren
|
||||
|
||||
habe mir ueberlegt, mal eben prometheus/loki etc drumrumzubauen, aber Zeit, ...
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
theme: uncover
|
||||
_class: lead
|
||||
size: 16:9
|
||||
paginate: true
|
||||
footer: "SSH advanced uses - Felix"
|
||||
marp: true
|
||||
backgroundColor: #fff
|
||||
backgroundImage: url('https://marp.app/assets/hero-background.svg')
|
||||
---
|
||||
# **SSH advanced uses**
|
||||
|
||||
Cool things you can do with **ssh** beyond the basics
|
||||
<span style="color: darkgrey; font-size: 0.5em">(**s**ecure **sh**ell, though nobody calls it that)</span>
|
||||
|
||||
---
|
||||
## TOC
|
||||
1. [Port forwarding](#port-forwarding)
|
||||
2. [ProxyJump](#proxyjump)
|
||||
3. [Certificates](#certificates)
|
||||
4. [X11 forwarding](#x11)
|
||||
5. [outdated hosts](#modern-client-old-hosts)
|
||||
6. Control channel reuse
|
||||
7. ssh_config best practices & tricks
|
||||
---
|
||||
# Port forwarding
|
||||
|
||||
---
|
||||
# ProxyJump
|
||||
The problem: *remote-server* can only be accessed from *jumphost*, so you need to connect to *jumphost* first and then connect to *remote-server*.
|
||||
<!-- Most people instinctively log onto the jumphost into an interactive shell, then use the jumphost's ssh to connect to their intended destination (remote-server). This creates many problems, most glaringly you have to expose your authentication credentials to the jumphost. As discussed in the basics, you *never* put your private key onto a machine that is not your personal workstation, and you never forward agent to a system where you are not root and trust the other co-roots (and even then it's discouraged).
|
||||
A large problem usually arises when people need to copy files from *client* to *remote-server*, because often times the jumphost is an aging solaris machine with 50MB user quota or something like that.
|
||||
-->
|
||||
|
||||
openssh from ca 2016 on allows you to do
|
||||
```ssh -J user@jumphost root@remote-server```
|
||||
<!-- This creates port forwarding under the hood, first making a connection from *client* to *jumphost* with port forwarding, then a second connection from client to the remote ports on jumphost -->
|
||||
|
||||
---
|
||||
# Certificates
|
||||
|
||||
Awesome!
|
||||
|
||||
---
|
||||
|
||||
## create CA
|
||||
```ssh-keygen -f my_ssh_cert_authority```
|
||||
<!-- yes, the same command as a regular ssh key - this is just a regular ssh key! -->
|
||||
|
||||
---
|
||||
|
||||
## sign a pubkey
|
||||
```ssh-keygen -V +1h -s my_ssh_cert_authority -I felix_via_cert my_test_user.pub```
|
||||
<!-- -V is the validity / lifetime of a signed cert; -s is the signing key, -I gives the pubkey to sign -->
|
||||
This creates ```my_test_user-cert.pub```, get this back to the user requesting access.
|
||||
|
||||
---
|
||||
### inspect a signed cert
|
||||
```ssh-keygen -L -f my_test_user-cert.pub```
|
||||
```
|
||||
my_test_user-cert.pub:
|
||||
Type: ssh-ed25519-cert-v01@openssh.com user certificate
|
||||
Public key: ED25519-CERT SHA256:VJyz194XhAw4HcMZ5uboj/35ZJyC9yNLP0lLtjiKCX8
|
||||
Signing CA: RSA SHA256:5Fs780JRzis+3lEreIZGoo+Ao7hKX8ksUU58cI58AyQ (using rsa-sha2-512)
|
||||
Key ID: "felix_via_cert"
|
||||
Serial: 0
|
||||
Valid: from 2024-07-14T13:46:00 to 2024-07-14T14:47:34
|
||||
Principals: (none)
|
||||
Critical Options: (none)
|
||||
Extensions:
|
||||
permit-X11-forwarding
|
||||
permit-agent-forwarding
|
||||
permit-port-forwarding
|
||||
permit-pty
|
||||
permit-user-rc
|
||||
```
|
||||
|
||||
---
|
||||
## use your shiny new cert
|
||||
|
||||
for openssh based systems, place the $IDENTITY-cert.pub file next to the $IDENTITY file. Make sure it has the correct permissions (of 0600), and it will be used automatically when you specify to use $IDENTITY.
|
||||
|
||||
---
|
||||
# X11
|
||||
- check out x2go
|
||||
|
||||
---
|
||||
# modern client, old hosts
|
||||
Increasingly often, I get old (older than 2016 or so) kit that does not let me connect
|
||||
@@ -0,0 +1,281 @@
|
||||
<!DOCTYPE html><html lang="en-US"><head><title>**SSH 101 with Felix**</title><meta property="og:title" content="**SSH 101 with Felix**"><meta charset="UTF-8"><meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0"><meta name="apple-mobile-web-app-capable" content="yes"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta property="og:type" content="website"><meta name="twitter:card" content="summary"><style>@media screen{body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button{appearance:none;background-color:initial;border:0;color:inherit;cursor:pointer;font-size:inherit;opacity:.8;outline:none;padding:0;transition:opacity .2s linear;-webkit-tap-highlight-color:transparent}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:disabled,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:disabled,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:disabled,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:disabled{cursor:not-allowed;opacity:.15!important}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover{opacity:1}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:active,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:active,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover:active,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover:active{opacity:.6}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:not(:disabled),body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:not(:disabled),body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover:not(:disabled),body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover:not(:disabled){transition:none}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button.bespoke-marp-presenter-info-page-prev{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNNjggOTAgMjggNTBsNDAtNDAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button.bespoke-marp-presenter-info-page-next{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJtMzIgOTAgNDAtNDAtNDAtNDAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=fullscreen],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=fullscreen]{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48ZGVmcz48c3R5bGU+LmF7ZmlsbDpub25lO3N0cm9rZTojZmZmO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6NXB4fTwvc3R5bGU+PC9kZWZzPjxyZWN0IHdpZHRoPSI4MCIgaGVpZ2h0PSI2MCIgeD0iMTAiIHk9IjIwIiBjbGFzcz0iYSIgcng9IjUuNjciLz48cGF0aCBkPSJNNDAgNzBIMjBWNTBtMjAgMEwyMCA3MG00MC00MGgyMHYyMG0tMjAgMCAyMC0yMCIgY2xhc3M9ImEiLz48L3N2ZLine truncated
|
||||
* Marp default theme.
|
||||
*
|
||||
* @theme default
|
||||
* @author Yuki Hattori
|
||||
*
|
||||
* @auto-scaling true
|
||||
* @size 16:9 1280px 720px
|
||||
* @size 4:3 960px 720px
|
||||
*/div#\:\$p > svg > foreignObject > section{--base-size-4:calc(var(--marpit-root-font-size, 1rem) * 0.25);--base-size-8:calc(var(--marpit-root-font-size, 1rem) * 0.5);--base-size-16:calc(var(--marpit-root-font-size, 1rem) * 1);--base-size-24:calc(var(--marpit-root-font-size, 1rem) * 1.5);--base-size-40:calc(var(--marpit-root-font-size, 1rem) * 2.5);--base-text-weight-normal:400;--base-text-weight-medium:500;--base-text-weight-semibold:600;--fontStack-monospace:ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;--fgColor-accent:Highlight;}div#\:\$p > svg > foreignObject > section [data-theme=light],div#\:\$p > svg > foreignObject > section{color-scheme:light;--focus-outlineColor:#0969da;--fgColor-default:#1f2328;--fgColor-muted:#59636e;--fgColor-accent:#0969da;--fgColor-success:#1a7f37;--fgColor-attention:#9a6700;--fgColor-danger:#d1242f;--fgColor-done:#8250df;--bgColor-default:#fff;--bgColor-muted:#f6f8fa;--bgColor-neutral-muted:#818b981f;--bgColor-attention-muted:#fff8c5;--borderColor-default:#d1d9e0;--borderColor-muted:#d1d9e0b3;--borderColor-neutral-muted:#d1d9e0b3;--borderColor-accent-emphasis:#0969da;--borderColor-success-emphasis:#1a7f37;--borderColor-attention-emphasis:#9a6700;--borderColor-danger-emphasis:#cf222e;--borderColor-done-emphasis:#8250df;--color-prettylights-syntax-comment:#59636e;--color-prettylights-syntax-constant:#0550ae;--color-prettylights-syntax-constant-other-reference-link:#0a3069;--color-prettylights-syntax-entity:#6639ba;--color-prettylights-syntax-storage-modifier-import:#1f2328;--color-prettylights-syntax-entity-tag:#0550ae;--color-prettylights-syntax-keyword:#cf222e;--color-prettylights-syntax-string:#0a3069;--color-prettylights-syntax-variable:#953800;--color-prettylights-syntax-brackethighlighter-unmatched:#82071e;--color-prettylights-syntax-brackethighlighter-angle:#59636e;--color-prettylights-syntax-invalid-illegal-text:#f6f8fa;--color-prettylights-syntax-invalid-illegal-bg:#82071e;--color-prettylights-syntax-carriage-return-text:#f6f8fa;--color-prettylights-syntax-carriage-return-bg:#cf222e;--color-prettylights-syntax-string-regexp:#116329;--color-prettylights-syntax-markup-list:#3b2300;--color-prettylights-syntax-markup-heading:#0550ae;--color-prettylights-syntax-markup-italic:#1f2328;--color-prettylights-syntax-markup-bold:#1f2328;--color-prettylights-syntax-markup-deleted-text:#82071e;--color-prettylights-syntax-markup-deleted-bg:#ffebe9;--color-prettylights-syntax-markup-inserted-text:#116329;--color-prettylights-syntax-markup-inserted-bg:#dafbe1;--color-prettylights-syntax-markup-changed-text:#953800;--color-prettylights-syntax-markup-changed-bg:#ffd8b5;--color-prettylights-syntax-markup-ignored-text:#d1d9e0;--color-prettylights-syntax-markup-ignored-bg:#0550ae;--color-prettylights-syntax-meta-diff-range:#8250df;--color-prettylights-syntax-sublimelinter-gutter-mark:#818b98;}div#\:\$p > svg > foreignObject > section [data-theme=dark],div#\:\$p > svg > foreignObject > section:where(.invert){color-scheme:dark;--focus-outlineColor:#1f6feb;--fgColor-default:#f0f6fc;--fgColor-muted:#9198a1;--fgColor-accent:#4493f8;--fgColor-success:#3fb950;--fgColor-attention:#d29922;--fgColor-danger:#f85149;--fgColor-done:#ab7df8;--bgColor-default:#0d1117;--bgColor-muted:#151b23;--bgColor-neutral-muted:#656c7633;--bgColor-attention-muted:#bb800926;--borderColor-default:#3d444d;--borderColor-muted:#3d444db3;--borderColor-neutral-muted:#3d444db3;--borderColor-accent-emphasis:#1f6feb;--borderColor-success-emphasis:#238636;--borderColor-attention-emphasis:#9e6a03;--borderColor-danger-emphasis:#da3633;--borderColor-done-emphasis:#8957e5;--color-prettylights-syntax-comment:#9198a1;--color-prettylights-syntax-constant:#79c0ff;--color-prettylights-syntax-constant-other-reference-link:#a5d6ff;--color-prettylights-syntax-entity:#d2a8ff;--color-prettylights-syntax-storage-modifier-import:#f0f6fc;--color-prettylights-syntax-entity-tag:#7ee787;--color-prettylights-syntax-keyword:#ff7b72;--color-prettylights-syntax-string:#a5d6ff;--color-prettylights-syntax-variable:#ffa657;--color-prettylights-syntax-brackethighlighter-unmatched:#f85149;--color-prettylights-syntax-brackethighlighter-angle:#9198a1;--color-prettylights-syntax-invalid-illegal-text:#f0f6fc;--color-prettylights-syntax-invalid-illegal-bg:#8e1519;--color-prettylights-syntax-carriage-return-text:#f0f6fc;--color-prettylights-syntax-carriage-return-bg:#b62324;--color-prettylights-syntax-string-regexp:#7ee787;--color-prettylights-syntax-markup-list:#f2cc60;--color-prettylights-syntax-markup-heading:#1f6feb;--color-prettylights-syntax-markup-italic:#f0f6fc;--color-prettylights-syntax-markup-bold:#f0f6fc;--color-prettylights-syntax-markup-deleted-text:#ffdcd7;--color-prettylights-syntax-markup-deleted-bg:#67060c;--color-prettylights-syntax-markup-inserted-text:#aff5b4;--color-prettylights-syntax-markup-inserted-bg:#033a16;--color-prettylights-syntax-markup-changed-text:#ffdfb6;--color-prettylights-syntax-markup-Line truncated
|
||||
</style></head><body><div class="bespoke-marp-osc"><button data-bespoke-marp-osc="prev" tabindex="-1" title="Previous slide">Previous slide</button><span data-bespoke-marp-osc="page"></span><button data-bespoke-marp-osc="next" tabindex="-1" title="Next slide">Next slide</button><button data-bespoke-marp-osc="fullscreen" tabindex="-1" title="Toggle fullscreen (f)">Toggle fullscreen</button><button data-bespoke-marp-osc="presenter" tabindex="-1" title="Open presenter view (p)">Open presenter view</button></div><div id=":$p"><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section data-paginate="true" data-background-color="#fff" data-background-image="" data-class="lead" data-footer="SSH 101 - Felix" data-theme="default" lang="en-US" class="lead" data-marpit-pagination="1" style="--paginate:true;--background-color:#fff;--background-image:;--class:lead;--footer:SSH 101 - Felix;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="background"><div data-marpit-advanced-background-container="true" data-marpit-advanced-background-direction="horizontal"><figure style="background-image:url("./img/artbreeder-composer-2024-07-15T00_14_43.169Z.jpeg");filter:opacity(0.15);"></figure></div></section></foreignObject><foreignObject width="1280" height="720"><section id="1" data-paginate="true" data-background-color="#fff" data-background-image="" data-class="lead" data-footer="SSH 101 - Felix" data-theme="default" lang="en-US" class="lead" data-marpit-pagination="1" style="--paginate:true;--background-color:#fff;--background-image:;--class:lead;--footer:SSH 101 - Felix;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="content">
|
||||
<h1 id="ssh-101-with-felix"><strong>SSH 101 with Felix</strong></h1>
|
||||
<p>Things everybody assumes you already know about <strong>ssh</strong><br />
|
||||
<span style="color: darkgrey; font-size: 0.7em">(<strong>s</strong>ecure <strong>sh</strong>ell, though nobody calls it that)</span></p>
|
||||
<p>Felix Schüren<br />
|
||||
2025-11-09 DENOG17 Essen</p>
|
||||
<p><span style="color: darkgrey; font-size: 0.4em"><a href="https://www.artbreeder.com/image/1dd1d0aa30538254292cc9c4ee5e">Background illustration</a> created with <a href="https://www.artbreeder.com/">Artbreeder</a></span></p>
|
||||
<footer>SSH 101 - Felix</footer>
|
||||
</section>
|
||||
</foreignObject><foreignObject width="1280" height="720" data-marpit-advanced-background="pseudo"><section data-paginate="true" data-background-color="#fff" data-background-image="" data-class="lead" data-footer="SSH 101 - Felix" data-theme="default" lang="en-US" class="lead" data-marpit-pagination="1" style="" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="pseudo"></section></foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-marpit-fragments="5" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="2" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="intro">Intro</h1>
|
||||
<ul>
|
||||
<li>Which of you...
|
||||
<ul>
|
||||
<li data-marpit-fragment="1">use ssh already?</li>
|
||||
<li data-marpit-fragment="2">use port forwarding?</li>
|
||||
<li data-marpit-fragment="3">use ProxyJump?</li>
|
||||
<li data-marpit-fragment="4">use ssh certificates?</li>
|
||||
<li data-marpit-fragment="5">use Windows? MacOS? Linux? Something else?</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="3" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="timeline-ideas">Timeline ideas</h1>
|
||||
<ul>
|
||||
<li>passwordless login</li>
|
||||
<li>port forwarding</li>
|
||||
<li>jumphosts, agent forwarding, proxyjump</li>
|
||||
<li>host_keys / mitm</li>
|
||||
<li>ssh_config</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="4" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="ideas">ideas</h1>
|
||||
<ul>
|
||||
<li>Im laufenden Lab auf einem jumphost die host_keys ändern, um Warnungen zu produzieren</li>
|
||||
<li>agent_forwarding abgreifen und mich als einen der User einloggen</li>
|
||||
<li>Hinterher aufzeigen (frei nach "I've been here the whole time!"), dass man cert-based logins benutzt hat</li>
|
||||
<li>ggfs Stacy Fakename, Joanna Fakename als Easter eggs?</li>
|
||||
<li>wie baue ich eine gute ssh_config</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="5" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="background" data-marpit-advanced-background-split="right"><div data-marpit-advanced-background-container="true" data-marpit-advanced-background-direction="horizontal"><figure style="background-image:url("./img/artbreeder-composer-2024-07-14T22_49_42.899Z.jpeg");"></figure></div></section></foreignObject><foreignObject width="50%" height="720"><section id="5" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="5" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="content" data-marpit-advanced-background-split="right">
|
||||
<ol>
|
||||
<li><a href="#how">How?</a></li>
|
||||
<li><a href="#host-keys">Host Keys</a></li>
|
||||
<li><a href="#key-based-authentication">Key-based auth</a></li>
|
||||
<li><a href="#ssh-agent">SSH Agent</a></li>
|
||||
<li><a href="#agent-forwarding">Agent forwarding</a></li>
|
||||
</ol>
|
||||
<p><span style="color: darkgrey; font-size: 0.4em"><a href="https://www.artbreeder.com/image/f1f2dd42df55daa49ddcea6db222">Illustration</a> created with <a href="https://www.artbreeder.com/">Artbreeder</a></span></p>
|
||||
</section>
|
||||
</foreignObject><foreignObject width="1280" height="720" data-marpit-advanced-background="pseudo"><section data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="5" style="" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="pseudo" data-marpit-advanced-background-split="right"></section></foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="6" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="how">how?</h1>
|
||||
<p>The essence behind SSH is asymmetric cryptography<br />
|
||||
<span style="color: darkgrey; font-size: 0.5em">(public/private key cryptography)</span></p>
|
||||
<ol>
|
||||
<li>you give others a "servant key" (public key)
|
||||
<ul>
|
||||
<li>can only be used to encrypt data</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>you keep the master key (private key)
|
||||
<ul>
|
||||
<li>this decrypts the data that was encrypted with 1.</li>
|
||||
<li>keep this <strong>very secure</strong>, never give it away.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="7" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="host-keys">host keys</h1>
|
||||
<p>Very similar concept to user/client keys, the host/server also has a private/public key pair</p>
|
||||
<ul>
|
||||
<li>live in <code>/etc/ssh/</code>, typically called <code>ssh_host_$TYPE_key</code></li>
|
||||
<li>be mindful of this when templating/cloning VMs or containers</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="8" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h2 id="known_hosts-and-you">known_hosts and you</h2>
|
||||
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>The authenticity of host 'schmargonrog.example.com' can't be established.
|
||||
ED25519 key fingerprint is SHA256:H49twPDi0au3WObFIUmrbUSqc2j8uYzb2BCDigttvbw.
|
||||
This key is not known by any other names.
|
||||
Are you sure you want to continue connecting (yes/no/[fingerprint])?
|
||||
</code></pre>
|
||||
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
|
||||
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
|
||||
It is also possible that a host key has just been changed.
|
||||
The fingerprint for the ED25519 key sent by the remote host is
|
||||
SHA256:s7Z+oc2AUQUqNH91OPkqzL0VXbe2fAoF+p+robhrCv0.
|
||||
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
|
||||
Offending ECDSA key in /root/.ssh/known_hosts:71
|
||||
remove with:
|
||||
ssh-keygen -f "/root/.ssh/known_hosts" -R "clab-f2-spine2"
|
||||
[...]
|
||||
Host key verification failed.
|
||||
</code></pre>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="9" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h2 id="how-does-it-keep-track-of-known-hosts">how does it keep track of known hosts?</h2>
|
||||
|
||||
<p><code>~/.ssh/known_hosts</code> (personal) or <code>/etc/ssh/ssh_known_hosts</code> (global)</p>
|
||||
<ul>
|
||||
<li>lists hostname, ssh key type and public key for hosts you have previously connected to<pre is="marp-pre" data-auto-scaling="downscale-only"><code>server1.example.com ssh-ed25519 AAAAC3NzaC1lZ...
|
||||
server1.example.com ssh-rsa AAAAB3NzaC1yc2E...
|
||||
server1.example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLX...
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>some Linux distros default to <code>HashKnownHosts yes</code>, which replaces the hostname with a hashed version<pre is="marp-pre" data-auto-scaling="downscale-only"><code>|1|32Q6...=|Ul+EoN...= ssh-ed25519 AAAAC3NzaC1l...
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section data-marpit-scope-V2kr4t0K="" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="10" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="background" data-marpit-advanced-background-split="left"><div data-marpit-advanced-background-container="true" data-marpit-advanced-background-direction="horizontal"><figure style="background-image:url("./img/adam-winger-GIFlfKX23rc-unsplash.jpg");background-size:70%;"></figure></div></section></foreignObject><foreignObject width="50%" height="720" x="50%"><section id="10" data-marpit-scope-V2kr4t0K="" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="10" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="content" data-marpit-advanced-background-split="left">
|
||||
<p>To recap:</p>
|
||||
<ul>
|
||||
<li>temp pub/priv keys used to establish connection & share the session secret
|
||||
<ul>
|
||||
<li>from this point on, all comms on the ssh session are protected by this session secret</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><code>known_hosts</code> important to prevent man-in-the-middle attacks</li>
|
||||
</ul>
|
||||
|
||||
<p><span style="color: darkgrey; font-size: 0.4em">Photo by <a href="https://unsplash.com/@awcreativeut?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Adam Winger</a> on <a href="https://unsplash.com/photos/girl-writing-on-the-ground-using-a-spray-an-GIFlfKX23rc?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></span></p>
|
||||
</section>
|
||||
</foreignObject><foreignObject width="1280" height="720" data-marpit-advanced-background="pseudo"><section data-marpit-scope-V2kr4t0K="" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="10" style="" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="pseudo" data-marpit-advanced-background-split="left"></section></foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="11" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="background" data-marpit-advanced-background-split="right"><div data-marpit-advanced-background-container="true" data-marpit-advanced-background-direction="horizontal"><figure style="background-image:url("./img/cajeo-zhang-EbOAPSCwjnU-unsplash.jpg");"></figure></div></section></foreignObject><foreignObject width="50%" height="720"><section id="11" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="11" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="content" data-marpit-advanced-background-split="right">
|
||||
<h1 id="part-2">Part 2</h1>
|
||||
<h3 id="the-two-pillars">The Two Pillars</h3>
|
||||
|
||||
<ul>
|
||||
<li>Key based auth</li>
|
||||
<li>ssh agent</li>
|
||||
</ul>
|
||||
|
||||
<p><span style="color: darkgrey; font-size: 0.4em">Photo by <a href="https://unsplash.com/@cajeo?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Cajeo Zhang</a> on <a href="https://unsplash.com/photos/gray-rock-formation-during-daytime-EbOAPSCwjnU?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></span></p>
|
||||
</section>
|
||||
</foreignObject><foreignObject width="1280" height="720" data-marpit-advanced-background="pseudo"><section data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="11" style="" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="pseudo" data-marpit-advanced-background-split="right"></section></foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="12" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="key-based-authentication">Key-based authentication</h1>
|
||||
<ul>
|
||||
<li>A private (secret, <strong>only for you</strong>) key
|
||||
<ul>
|
||||
<li><strong>never</strong> give this to anyone else</li>
|
||||
<li><strong>never</strong> copy this to another machine</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>A public (everyone can have it) key
|
||||
<ul>
|
||||
<li><small>can be generated from the private key</small></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>typically, <code>id_rsa</code> and <code>id_rsa.pub</code>
|
||||
<ul>
|
||||
<li><small>or <code>id_ed25519</code>, <code>id_dsa</code>, ...</small></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="13" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h2 id="how-to-generate-a-key-pair">how to generate a key pair</h2>
|
||||
<ul>
|
||||
<li><code>ssh-keygen -t rsa -b 4096</code>
|
||||
<ul>
|
||||
<li>will create <code>~/.ssh/id_rsa</code> and <code>~/.ssh/id_rsa.pub</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><code>ssh-keygen -t ed25519</code>
|
||||
<ul>
|
||||
<li>→<code>id_ed25519</code>, essentially, it's <code>id_$TYPE</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>please, do set a passphrase for the key. I will explain how to make it not annoying.</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="14" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h2 id="and-now-aka-authorized_keys">and now? aka <code>authorized_keys</code></h2>
|
||||
|
||||
<p>You now put the <strong>public</strong> key into the <code>~/.ssh/authorized_keys</code> file of the user/host combination you want to have access to.</p>
|
||||
<pre is="marp-pre" data-auto-scaling="downscale-only"><code># cat ~/.ssh/authorized_keys
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA6Gc/53b0ZBGL/ORF5hIa61hTPTAsrjnkxXl3wawsHT felix@home
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEx6jIZeHFxh1NDJOoHGQLg0ViqqFNKGd5ofTRvHb4Fh backuppc@backup
|
||||
</code></pre>
|
||||
|
||||
<p><span style="color: orange; font-size: 0.5em">(Remember, do not give your private key to anyone. Never.)</span></p>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="15" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h2 id="example-login">example login</h2>
|
||||
<p>having added the contents of my <code>~/.ssh/id_ed25519.pub</code> file to the user <code>root</code> on my server <code>db.example.com</code>, I can now do</p>
|
||||
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>ssh -i ~/.ssh/id_ed25519 root@db.example.com
|
||||
</code></pre>
|
||||
<p>My local SSH client will ask me for my passphrase (to unlock the private key into memory), then use the private key to authenticate me, allowing me to log in.</p>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="16" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="ssh-agent">SSH agent</h1>
|
||||
<ul>
|
||||
<li>Stores unlocked private keys in memory</li>
|
||||
<li>only enter your passphrase when adding the key to the in-memory store</li>
|
||||
<li>configurable lifetime
|
||||
<ul>
|
||||
<li>I would recommend 8-10 hours, so that during normal working hours you enter your passphrase once per day.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Painless passwordless logins!</li>
|
||||
<li>can either manually add keys to it using <code>ssh-add</code> or set <code>AddKeysToAgent yes</code> in your ssh config</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="17" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<h1 id="agent-forwarding">Agent forwarding</h1>
|
||||
<ul>
|
||||
<li>Exposes your private key cache (the "agent") to the system you're connecting to
|
||||
<ul>
|
||||
<li><code>SSH_AUTH_SOCK</code> environment variable</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<pre is="marp-pre" data-auto-scaling="downscale-only"><code># echo $SSH_AUTH_SOCK
|
||||
/tmp/ssh-XXXXiA23DL/agent.1337770
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li>allows you to access your private keys from an intermediary system
|
||||
<ul>
|
||||
<li>but everyone with root rights on the intermediary can use your SSH_AUTH_SOCK!</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section data-marpit-scope-M4fzojr9="" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="18" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="background" data-marpit-advanced-background-split="left"><div data-marpit-advanced-background-container="true" data-marpit-advanced-background-direction="horizontal"><figure style="background-image:url("./img/jonatan-david-K7MkzR7rBmM-unsplash.jpg");background-size:70%;"></figure></div></section></foreignObject><foreignObject width="50%" height="720" x="50%"><section id="18" data-marpit-scope-M4fzojr9="" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="18" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;--marpit-advanced-background-split:50%;" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="content" data-marpit-advanced-background-split="left">
|
||||
<h1 id="finished">Finished</h1>
|
||||
|
||||
<ul>
|
||||
<li>keep your private key very private</li>
|
||||
<li>be very careful with agent forwarding</li>
|
||||
<li>be paranoid with <code>known_hosts</code></li>
|
||||
<li>check out the manpage of the ssh client config: <code>man ssh_config</code></li>
|
||||
<li>visit the advanced workshop</li>
|
||||
</ul>
|
||||
|
||||
<p><span style="color: darkgrey; font-size: 0.4em">Photo by <a href="https://unsplash.com/@bboy_mocachino?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Jonatan David</a> on <a href="https://unsplash.com/photos/a-blurry-photo-of-a-street-with-a-stop-sign-K7MkzR7rBmM?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></span></p>
|
||||
</section>
|
||||
</foreignObject><foreignObject width="1280" height="720" data-marpit-advanced-background="pseudo"><section data-marpit-scope-M4fzojr9="" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="18" style="" data-marpit-pagination-total="20" data-size="16:9" data-marpit-advanced-background="pseudo" data-marpit-advanced-background-split="left"></section></foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="19" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<p>Teaser: Ich wollte eh auf der DENOG Workshop fuer ssh machen, gebe hier mal Teaser, Rest koennt ihr dann euch selber angucken, ...</p>
|
||||
<p>Praxis-Fails einbauen - neue hostkeys, passwort eingeben muessen, passphrase, ... jetzt muss ich meinen private key auf den jumphost kopieren, nein doch nicht, .... teaser-problem fuer proxyjump</p>
|
||||
<p>optional proxyjump, falls ich zu schnell durchgehe bzw generell mal fragen, ob weiteres Interesse besteht</p>
|
||||
<p>fuer lab: ein ssh-container-labyrinth, proxyjumps aussenrum und dann zum Schluss mit einem einzelnen ssh-kommando dateien aus der Mitte nach aussen... oder so.</p>
|
||||
</section>
|
||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-paginate="true" data-background-color="#fff" data-background-image="" data-theme="default" lang="en-US" data-marpit-pagination="20" style="--paginate:true;--background-color:#fff;--background-image:;--theme:default;background-color:#fff;background-image:;background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="20" data-size="16:9">
|
||||
<p><a href="https://www.openssh.com/legacy.html">https://www.openssh.com/legacy.html</a><br />
|
||||
KexAlgorithms: the key exchange methods that are used to generate per-connection keys<br />
|
||||
HostkeyAlgorithms: the public key algorithms accepted for an SSH server to authenticate itself to an SSH client<br />
|
||||
Ciphers: the ciphers to encrypt the connection<br />
|
||||
MACs: the message authentication codes used to detect traffic modification<br />
|
||||
<code>ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 user@legacyhost</code><br />
|
||||
<code>ssh -oHostKeyAlgorithms=+ssh-dss user@legacyhost</code></p>
|
||||
</section>
|
||||
<script>!function(){"use strict";const t={h1:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"1"},style:"display: block; font-size: 2em; margin-block-start: 0.67em; margin-block-end: 0.67em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h2:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"2"},style:"display: block; font-size: 1.5em; margin-block-start: 0.83em; margin-block-end: 0.83em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h3:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"3"},style:"display: block; font-size: 1.17em; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h4:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"4"},style:"display: block; margin-block-start: 1.33em; margin-block-end: 1.33em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h5:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"5"},style:"display: block; font-size: 0.83em; margin-block-start: 1.67em; margin-block-end: 1.67em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h6:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"6"},style:"display: block; font-size: 0.67em; margin-block-start: 2.33em; margin-block-end: 2.33em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},span:{proto:()=>HTMLSpanElement},pre:{proto:()=>HTMLElement,style:"display: block; font-family: monospace; white-space: pre; margin: 1em 0; --marp-auto-scaling-white-space: pre;"}},e="data-marp-auto-scaling-wrapper",i="data-marp-auto-scaling-svg",n="data-marp-auto-scaling-container";class s extends HTMLElement{container;containerSize;containerObserver;svg;svgComputedStyle;svgPreserveAspectRatio="xMinYMid meet";wrapper;wrapperSize;wrapperObserver;constructor(){super();const t=t=>([e])=>{const{width:i,height:n}=e.contentRect;this[t]={width:i,height:n},this.updateSVGRect()};this.attachShadow({mode:"open"}),this.containerObserver=new ResizeObserver(t("containerSize")),this.wrapperObserver=new ResizeObserver(((...e)=>{t("wrapperSize")(...e),this.flushSvgDisplay()}))}static get observedAttributes(){return["data-downscale-only"]}connectedCallback(){this.shadowRoot.innerHTML=`\n<style>\n svg[${i}] { display: block; width: 100%; height: auto; vertical-align: top; }\n span[${n}] { display: table; white-space: var(--marp-auto-scaling-white-space, nowrap); width: max-content; }\n</style>\n<div ${e}>\n <svg part="svg" ${i}>\n <foreignObject><span ${n}><slot></slot></span></foreignObject>\n </svg>\n</div>\n `.split(/\n\s*/).join(""),this.wrapper=this.shadowRoot.querySelector(`div[${e}]`)??void 0;const t=this.svg;this.svg=this.wrapper?.querySelector(`svg[${i}]`)??void 0,this.svg!==t&&(this.svgComputedStyle=this.svg?window.getComputedStyle(this.svg):void 0),this.container=this.svg?.querySelector(`span[${n}]`)??void 0,this.observe()}disconnectedCallback(){this.svg=void 0,this.svgComputedStyle=void 0,this.wrapper=void 0,this.container=void 0,this.observe()}attributeChangedCallback(){this.observe()}flushSvgDisplay(){const{svg:t}=this;t&&(t.style.display="inline",requestAnimationFrame((()=>{t.style.display=""})))}observe(){this.containerObserver.disconnect(),this.wrapperObserver.disconnect(),this.wrapper&&this.wrapperObserver.observe(this.wrapper),this.container&&this.containerObserver.observe(this.container),this.svgComputedStyle&&this.observeSVGStyle(this.svgComputedStyle)}observeSVGStyle(t){const e=()=>{const i=(()=>{const e=t.getPropertyValue("--preserve-aspect-ratio");if(e)return e.trim();return`x${(({textAlign:t,direction:e})=>{if(t.endsWith("left"))return"Min";if(t.endsWith("right"))return"Max";if("start"===t||"end"===t){let i="rtl"===e;return"end"===t&&(i=!i),i?"Max":"Min"}return"Mid"})(t)}YMid meet`})();i!==this.svgPreserveAspectRatio&&(this.svgPreserveAspectRatio=i,this.updateSVGRect()),t===this.svgComputedStyle&&requestAnimationFrame(e)};e()}updateSVGRect(){let t=Math.ceil(this.containerSize?.width??0);const e=Math.ceil(this.containerSize?.height??0);void 0!==this.dataset.downscaleOnly&&(t=Math.max(t,this.wrapperSize?.width??0));const i=this.svg?.querySelector(":scope > foreignObject");if(i?.setAttribute("width",`${t}`),i?.setAttribute("height",`${e}`),this.svg&&(this.svg.setAttribute("viewBox",`0 0 ${t} ${e}`),this.svg.setAttribute("preserveAspectRatio",this.svgPreserveAspectRatio),this.svg.style.height=t<=0||e<=0?"0":""),this.container){const t=this.svgPreserveAspectRatio.toLowerCase();this.container.style.marginLeft=t.startsWith("xmid")||t.startsWith("xmax")?"auto":"0",this.container.style.marginRight=t.startsWith("xmi")?"auto":"0"}}}const r=(t,{attrs:e={},style:i})=>class extends t{constructor(...t){super(...t);for(const[t,i]of Object.entries(e))this.hasAttribute(t)||this.setAttribute(t,i);this._shadow()}static get observedAttributes(){return["data-auto-scaling"]}connectedCallLine truncated
|
||||
</script></foreignObject></svg></div><div class="bespoke-marp-note" data-index="0" tabindex="0"><p>This is aimed at people using SSH in their daily work - it does not deal with details of the SSH protocol itself.</p></div><div class="bespoke-marp-note" data-index="5" tabindex="0"><p>pubkey can also check signatures, but that's less important in ssh use.</p><p>This enables one-way secure communication - others can now send data to you that
|
||||
can not be read or changed on the way to you. That's great, but you want to communicate bi-directionally...</p></div><div class="bespoke-marp-note" data-index="6" tabindex="0"><p>Now both parties (client and server) have a way to receive encrypted messages, and as mentionend use this to share a session secret (for efficiency and speed) for running sessions.
|
||||
Under the hood, SSH will use temporary pub/priv keys to establish the connection, then switch to symmetric encryption where the shared secret is randomly generated between the
|
||||
SSH parties and transmitted securely through the magic of pub/priv crypto.</p></div><div class="bespoke-marp-note" data-index="7" tabindex="0"><p>you will have seen a message popping up when you connect to a new host for the first time, displaying some form of</p><p>Another message you might have seen is this one:</p><p>In both cases, you should think about what is going on. First case is pretty normal, you're connecting to a host that you have no previous information on. It's usually okay to say yes here. For the extra paranoid, verify the host key fingerprint through a secure side channel (phone? DNS? photo? etc...) before continuing the connection.
|
||||
|
||||
Don't follow the second message blindly say yes, think about *why* the host key might have changed. Did you recently do a dist-upgrade, did someone reinstall the machine without backing up/restoring the host keys, or was there a major breaking change with ssh during a system upgrade run? In any case, be vigilant.</p></div><div class="bespoke-marp-note" data-index="8" tabindex="0"><p>If you said "yes" on the prior page, how does your local ssh client actually save this information? There are two spaces, with the global one usually not being used.</p><p>(this is what happens when you answer "yes" on the first connection to a host and )</p><p>This makes some deleting entries a lot harder than before, and it might break some tab-completion magic that might use the known_hosts file</p><p>You might want to roll out the known_hosts centrally.</p></div><div class="bespoke-marp-note" data-index="9" tabindex="0"><p>Right, that's the basic how. Let's get to some things that make your life so much easier, yet that are often misunderstood.</p></div><div class="bespoke-marp-note" data-index="10" tabindex="0"><p>The most widely used yet often misunderstood features of SSH. This is why you are here.</p></div><div class="bespoke-marp-note" data-index="11" tabindex="0"><p>One of the core failures of the whole SSH ecosystem is the default naming convention for private/public keys. Accidentally cat'ing your private key is way too easy.
|
||||
|
||||
rsa, dsa, ed25519 are different variants/types of encryption. When in doubt, use RSA.
|
||||
|
||||
(I would always go with ED25519 for modern deployments, though it might not work on systems that are older than 2020ish)</p></div><div class="bespoke-marp-note" data-index="12" tabindex="0"><p>Securing your private key with a passphrase (which just means "long password") is a good precaution, it means somebody that gets access to your private key cannot immediately use it.</p></div><div class="bespoke-marp-note" data-index="13" tabindex="0"><p>Okay, now you have your key, and you can give the public side of it to others. If others want to securely encrypt something that **only** you can decrypt, they use your **public** key to encrypt. You then use your **private** key to decrypt.</p><p>In order to use this for authentication instead of a password, the SSH server will essentially encrypt something with your public key and ask you to send the decrypted text back (to prove that you are indeed in posession of the private key part)</p><p>*READABLE* && pubkey &rarr; *CRYPTED* && privkey &rarr; *READABLE*</p></div><div class="bespoke-marp-note" data-index="14" tabindex="0"><p>Yes, this feels identical to logging in with a password, except I was encouraged to make my passphrase longer and more annoying to type. Great job, you've made using ssh more annoying.</p></div><div class="bespoke-marp-note" data-index="15" tabindex="0"><p>Should probably more accurately be called the SSH private key cache. It's well integrated into openssh, and normal ssh connection attempts will try to use your local ssh agent automatically.</p><p>On macos, you can use the system keychain to store the passphrase, where they will live together with all the other saved passwords, protected by a master password. It's ```UseKeychain yes
|
||||
``` in your .ssh/config, and I would recommend to use that if you're on a mac.</p><p>On windows, putty has "pageant" to serve as private key cache, it works identically, though by default does not set a lifetime (you do need to re-enter passphrase after rebooting)</p><p>This is a must-have if you're serious about using key-based auth. You can get by with using keys without passphrase, but please don't, it carries a heavy price in terms of identity theft and potential damage to your reputation. As a sidenote, with more and more machines ending up in an MDM (mobile device management) "friendly rootkit" scenario, your private keys, passphrases and logins etc are essentially all compromised (to your MDM admins), making (digital) identity inside your company all but meaningless, but that is a topic for another talk... or hit me up later, I will talk at length about the problems I see with MDM :)</p></div><div class="bespoke-marp-note" data-index="16" tabindex="0"><p>you have essentially compromised your keys to every admin of the intermediary system. Be very, very careful where you agent forward to. Come visit my advanced SSH workshop to learn a better way.</p></div><div class="bespoke-marp-note" data-index="17" tabindex="0"><p></p><p>This covers what I consider the SSH 101</p></div><script>/*!! License: https://unpkg.com/@marp-team/marp-cli@4.2.2/lib/bespoke.js.LICENSE.txt */
|
||||
!function(){"use strict";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,n,r=(n||(n=1,t={from:function(e,t){var n,r=1===(e.parent||e).nodeType?e.parent||e:document.querySelector(e.parent||e),o=[].filter.call("string"==typeof e.slides?r.querySelectorAll(e.slides):e.slides||r.children,function(e){return"SCRIPT"!==e.nodeName}),a={},i=function(e,t){return(t=t||{}).index=o.indexOf(e),t.slide=e,t},s=function(e,t){a[e]=(a[e]||[]).filter(function(e){return e!==t})},c=function(e,t){return(a[e]||[]).reduce(function(e,n){return e&&!1!==n(t)},!0)},l=function(e,t){o[e]&&(n&&c("deactivate",i(n,t)),n=o[e],c("activate",i(n,t)))},d=function(e,t){var r=o.indexOf(n)+e;c(e>0?"next":"prev",i(n,t))&&l(r,t)},u={off:s,on:function(e,t){return(a[e]||(a[e]=[])).push(t),s.bind(null,e,t)},fire:c,slide:function(e,t){if(!arguments.length)return o.indexOf(n);c("slide",i(o[e],t))&&l(e,t)},next:d.bind(null,1),prev:d.bind(null,-1),parent:r,slides:o,destroy:function(e){c("destroy",i(n,e)),a={}}};return(t||[]).forEach(function(e){e(u)}),n||l(0),u}}),t),o=e(r);const a=document.body,i=(...e)=>history.replaceState(...e),s="",c="presenter",l="next",d=["",c,l],u="bespoke-marp-",f=`data-${u}`,m=(e,{protocol:t,host:n,pathname:r,hash:o}=location)=>{const a=e.toString();return`${t}//${n}${r}${a?"?":""}${a}${o}`},g=()=>a.dataset.bespokeView,p=e=>new URLSearchParams(location.search).get(e),v=(e,t={})=>{const n={location,setter:i,...t},r=new URLSearchParams(n.location.search);for(const t of Object.keys(e)){const n=e[t];"string"==typeof n?r.set(t,n):r.delete(t)}try{n.setter({...window.history.state??{}},"",m(r,n.location))}catch(e){console.error(e)}},h=(()=>{const e="bespoke-marp";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch{return!1}})(),y=e=>{try{return localStorage.getItem(e)}catch{return null}},b=(e,t)=>{try{return localStorage.setItem(e,t),!0}catch{return!1}},w=e=>{try{return localStorage.removeItem(e),!0}catch{return!1}},x=(e,t)=>{const n="aria-hidden";t?e.setAttribute(n,"true"):e.removeAttribute(n)},k=e=>{e.parent.classList.add(`${u}parent`),e.slides.forEach(e=>e.classList.add(`${u}slide`)),e.on("activate",t=>{const n=`${u}active`,r=t.slide,o=r.classList,a=!o.contains(n);if(e.slides.forEach(e=>{e.classList.remove(n),x(e,!0)}),o.add(n),x(r,!1),a){const e=`${n}-ready`;o.add(e),document.body.clientHeight,o.remove(e)}})},$=e=>{let t=0,n=0;Object.defineProperty(e,"fragments",{enumerable:!0,value:e.slides.map(e=>[null,...e.querySelectorAll("[data-marpit-fragment]")])});const r=r=>void 0!==e.fragments[t][n+r],o=(r,o)=>{t=r,n=o,e.fragments.forEach((e,t)=>{e.forEach((e,n)=>{if(null==e)return;const a=t<r||t===r&&n<=o;e.setAttribute(`${f}fragment`,(a?"":"in")+"active");const i=`${f}current-fragment`;t===r&&n===o?e.setAttribute(i,"current"):e.removeAttribute(i)})}),e.fragmentIndex=o;const a={slide:e.slides[r],index:r,fragments:e.fragments[r],fragmentIndex:o};e.fire("fragment",a)};e.on("next",({fragment:a=!0})=>{if(a){if(r(1))return o(t,n+1),!1;const a=t+1;e.fragments[a]&&o(a,0)}else{const r=e.fragments[t].length;if(n+1<r)return o(t,r-1),!1;const a=e.fragments[t+1];a&&o(t+1,a.length-1)}}),e.on("prev",({fragment:a=!0})=>{if(r(-1)&&a)return o(t,n-1),!1;const i=t-1;e.fragments[i]&&o(i,e.fragments[i].length-1)}),e.on("slide",({index:t,fragment:n})=>{let r=0;if(void 0!==n){const o=e.fragments[t];if(o){const{length:e}=o;r=-1===n?e-1:Math.min(Math.max(n,0),e-1)}}o(t,r)}),o(0,0)},E=document,L=()=>!(!E.fullscreenEnabled&&!E.webkitFullscreenEnabled),S=()=>!(!E.fullscreenElement&&!E.webkitFullscreenElement),P=e=>{e.fullscreen=()=>{L()&&(async()=>{S()?(E.exitFullscreen||E.webkitExitFullscreen)?.call(E):((e=E.body)=>{(e.requestFullscreen||e.webkitRequestFullscreen)?.call(e)})()})()},document.addEventListener("keydown",t=>{"f"!==t.key&&"F11"!==t.key||t.altKey||t.ctrlKey||t.metaKey||!L()||(e.fullscreen(),t.preventDefault())})},_=`${u}inactive`,T=(e=2e3)=>({parent:t,fire:n})=>{const r=t.classList,o=e=>n(`marp-${e?"":"in"}active`);let a;const i=()=>{a&&clearTimeout(a),a=setTimeout(()=>{r.add(_),o()},e),r.contains(_)&&(r.remove(_),o(!0))};for(const e of["mousedown","mousemove","touchend"])document.addEventListener(e,i);setTimeout(i,0)},I=["AUDIO","BUTTON","INPUT","SELECT","TEXTAREA","VIDEO"],M=e=>{e.parent.addEventListener("keydown",e=>{if(!e.target)return;const t=e.target;(I.includes(t.nodeName)||"true"===t.contentEditable)&&e.stopPropagation()})},O=e=>{window.addEventListener("load",()=>{for(const t of e.slides){const e=t.querySelector("marp-auto-scaling, [data-auto-scaling], [data-marp-fitting]");t.setAttribute(`${f}load`,e?"":"hideable")}})},A=({interval:e=250}={})=>t=>{document.addEventListener("keydown",e=>{if(" "===e.key&&e.shiftKey)t.prev();else if("ArrowLeft"===e.key||"ArrowUp"===e.key||"PageUp"===e.key)t.prev({fragment:!e.shiftKey});else if(" "!==e.key||e.shiftKey)if("ArrowRight"===e.key||"ArrowDown"===e.key||"PageDown"===e.key)t.next({fragment:!e.shiftKey});else if("End"===e.key)t.slLine truncated
|
||||
@@ -0,0 +1,341 @@
|
||||
---
|
||||
theme: sparta
|
||||
_class: lead
|
||||
size: 16:9
|
||||
paginate: true
|
||||
_footer: "SSH 101 - Felix"
|
||||
marp: true
|
||||
transition: fade
|
||||
lang: en
|
||||
backgroundColor: #fff
|
||||
xbackgroundImage: url('https://marp.app/assets/hero-background.svg')
|
||||
backgroundImage: 
|
||||
---
|
||||
|
||||
<!-- _class: title-academic -->
|
||||
|
||||

|
||||
|
||||
<div class="title" > SSH essentials</div>
|
||||
<div class="subtitle" > Stuff everybody assumes you already know about ssh </div>
|
||||
<div class="author" > Felix Schüren </div>
|
||||
<div class="date" > 2025-11-09</div>
|
||||
<div class="organization" > DENOG 17, Essen</div>
|
||||
|
||||
---
|
||||
# Intro
|
||||
## about me
|
||||
I've been doing networks for over 30 years by now. And DevOps stuff before we called it that.
|
||||
## about you
|
||||
- Which of you...
|
||||
* use ssh already?
|
||||
* use port forwarding?
|
||||
* use ProxyJump?
|
||||
* use ssh certificates?
|
||||
* use Windows? MacOS? Linux? Something else?
|
||||
|
||||
---
|
||||
# Clients
|
||||
## OpenSSH
|
||||
- Linux, Mac, Windows
|
||||
- just
|
||||
## but I need a GUI
|
||||
- A well-maintained ssh_config is usually better. And if you have too many hosts, you want to use ansible etc anyway.
|
||||
|
||||
---
|
||||
# Timeline ideas
|
||||
- clients
|
||||
<!-- On mac & linux, use openssh via a terminal app. It's usually preinstalled, if not, it comes with the base os packages. Same for windows (10+) - Use Terminal app + openssh. -->
|
||||
- passwordless login
|
||||
- port forwarding
|
||||
- jumphosts, agent forwarding, proxyjump
|
||||
- host_keys / mitm
|
||||
- ssh_config
|
||||
- vs code
|
||||
- identity files (multiple identities)
|
||||
|
||||
---
|
||||
# ~/.ssh permissions etc
|
||||
<!-- on some OSes (mostly Redhat derivatives) if key-based logins don't work, it's ofen to do with the permissions of the .ssh folder or the authorized_keys file. -->
|
||||
|
||||
---
|
||||
# ideas
|
||||
- Im laufenden Lab auf einem jumphost die host_keys ändern, um Warnungen zu produzieren
|
||||
- agent_forwarding abgreifen und mich als einen der User einloggen
|
||||
- Hinterher aufzeigen (frei nach "I've been here the whole time!"), dass man cert-based logins benutzt hat
|
||||
- ggfs Stacy Fakename, Joanna Fakename als Easter eggs?
|
||||
- wie baue ich eine gute ssh_config
|
||||
---
|
||||

|
||||
|
||||
1. [How?](#how)
|
||||
2. [Host Keys](#host-keys)
|
||||
3. [Key-based auth](#key-based-authentication)
|
||||
4. [SSH Agent](#ssh-agent)
|
||||
5. [Agent forwarding](#agent-forwarding)
|
||||
|
||||
<span style="color: darkgrey; font-size: 0.4em"><a href="https://www.artbreeder.com/image/f1f2dd42df55daa49ddcea6db222">Illustration</a> created with <a href="https://www.artbreeder.com/">Artbreeder</a></span>
|
||||
|
||||
---
|
||||
# SSH Agent
|
||||
## Windows
|
||||
```
|
||||
Set-Service ssh-agent -StartupType Automatic
|
||||
Start-Service ssh-agent
|
||||
```
|
||||
## Mac
|
||||
To add your ssh keys to MacOS Keychain, use `UseKeychain yes` in your ssh_config.
|
||||
|
||||
## Linux
|
||||
Generally, ssh- agent "just works". If not, simply
|
||||
|
||||
---
|
||||
# ssh_config
|
||||
- on Windows:
|
||||
`%USERPROFILE%\.ssh\config`
|
||||
- `PS C:\Users\felix>` `notepad.exe .\.ssh\config`
|
||||
- on Mac/Linux: `~/.ssh/config`
|
||||
|
||||
---
|
||||
# SSH Agent cont'd
|
||||
<!-- ssh agent usually works through the SSH_AUTH_SOCK and SSH_AGENT_PID variables. These variables are usually what's wrong with ssh-agent in a tmux or similar scenario. -->
|
||||
```
|
||||
root@clab:~/labs/ssh-workshop# ssh-agent
|
||||
SSH_AUTH_SOCK=/tmp/ssh-TzLLcOVtmlcY/agent.342525; export SSH_AUTH_SOCK;
|
||||
SSH_AGENT_PID=342526; export SSH_AGENT_PID;
|
||||
echo Agent pid 342526;
|
||||
```
|
||||
-> `eval $(ssh-agent -s)`
|
||||
<!-- When ssh-agent is started, it prints the shell commands required to set its environment variables, which in turn can be evaluated in the calling shell -->
|
||||
|
||||
---
|
||||
# Never use `ForwardAgent yes`.
|
||||
*ANYONE* with access to the SSH_AUTH_SOCK file can use the socket. (Generally, root. The directory is locked down as far as it will go, but root...)
|
||||
<!-- Live demo of how easy it is. Login as fred with AgentForward to a jumphost, demonstrate how the AgentForward works & helps fred to log in to webserver1, then have a second shell with root on the jumphost, demonstrate how root can't ssh to webserver1, manually set the correct SSH_AUTH_SOCK and watch how he suddenly can. -->
|
||||
|
||||
|
||||
---
|
||||
# ssh identities
|
||||
- ssh_config:
|
||||
```
|
||||
IdentityFile ~/.ssh/my-special-key
|
||||
IdentitiesOnly yes
|
||||
```
|
||||
---
|
||||
# how?
|
||||
The essence behind SSH is asymmetric cryptography
|
||||
<span style="color: darkgrey; font-size: 0.5em">(public/private key cryptography)</span>
|
||||
|
||||
1. you give others a "servant key" (public key)
|
||||
- can only be used to encrypt data<!-- pubkey can also check signatures, but that's less important in ssh use. -->
|
||||
2. you keep the master key (private key)
|
||||
- this decrypts the data that was encrypted with 1.
|
||||
- keep this **very secure**, never give it away.
|
||||
|
||||
<!-- This enables one-way secure communication - others can now send data to you that
|
||||
can not be read or changed on the way to you. That's great, but you want to communicate bi-directionally... -->
|
||||
|
||||
---
|
||||
# host keys
|
||||
Very similar concept to user/client keys, the host/server also has a private/public key pair
|
||||
- server (`sshd`) keys live in ```/etc/ssh/```, typically called ```ssh_host_$TYPE_key```
|
||||
- they are the "identity" of this particular ssh instance, they should be different on different machines
|
||||
- be mindful of this when templating/cloning VMs or containers
|
||||
<!-- Now both parties (client and server) have a way to receive encrypted messages, and as mentionend use this to share a session secret (for efficiency and speed) for running sessions.
|
||||
Under the hood, SSH will use temporary pub/priv keys to establish the connection, then switch to symmetric encryption where the shared secret is randomly generated between the
|
||||
SSH parties and transmitted securely through the magic of pub/priv crypto. -->
|
||||
|
||||
---
|
||||
## known_hosts and you
|
||||
<!-- you will have seen a message popping up when you connect to a new host for the first time, displaying some form of -->
|
||||
```
|
||||
The authenticity of host 'schmargonrog.example.com' can't be established.
|
||||
ED25519 key fingerprint is SHA256:H49twPDi0au3WObFIUmrbUSqc2j8uYzb2BCDigttvbw.
|
||||
This key is not known by any other names.
|
||||
Are you sure you want to continue connecting (yes/no/[fingerprint])?
|
||||
```
|
||||
<!-- Another message you might have seen is this one: -->
|
||||
```
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
|
||||
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
|
||||
It is also possible that a host key has just been changed.
|
||||
The fingerprint for the ED25519 key sent by the remote host is
|
||||
SHA256:s7Z+oc2AUQUqNH91OPkqzL0VXbe2fAoF+p+robhrCv0.
|
||||
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
|
||||
Offending ECDSA key in /root/.ssh/known_hosts:71
|
||||
remove with:
|
||||
ssh-keygen -f "/root/.ssh/known_hosts" -R "clab-f2-spine2"
|
||||
[...]
|
||||
Host key verification failed.
|
||||
```
|
||||
<!-- In both cases, you should think about what is going on. First case is pretty normal, you're connecting to a host that you have no previous information on. It's usually okay to say yes here. For the extra paranoid, verify the host key fingerprint through a secure side channel (phone? DNS? photo? etc...) before continuing the connection.
|
||||
|
||||
Don't follow the second message blindly say yes, think about *why* the host key might have changed. Did you recently do a dist-upgrade, did someone reinstall the machine without backing up/restoring the host keys, or was there a major breaking change with ssh during a system upgrade run? In any case, be vigilant.
|
||||
-->
|
||||
|
||||
---
|
||||
## how does it keep track of known hosts?
|
||||
<!-- If you said "yes" on the prior page, how does your local ssh client actually save this information? There are two spaces, with the global one usually not being used. -->
|
||||
```~/.ssh/known_hosts``` (personal) or ```/etc/ssh/ssh_known_hosts``` (global)
|
||||
- lists hostname, ssh key type and public key for hosts you have previously connected to
|
||||
```
|
||||
server1.example.com ssh-ed25519 AAAAC3NzaC1lZ...
|
||||
server1.example.com ssh-rsa AAAAB3NzaC1yc2E...
|
||||
server1.example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLX...
|
||||
```
|
||||
<!--- (this is what happens when you answer "yes" on the first connection to a host and )-->
|
||||
- some Linux distros default to ```HashKnownHosts yes```, which replaces the hostname with a hashed version
|
||||
```
|
||||
|1|32Q6...=|Ul+EoN...= ssh-ed25519 AAAAC3NzaC1l...
|
||||
```
|
||||
<!-- This makes some deleting entries a lot harder than before, and it might break some tab-completion magic that might use the known_hosts file -->
|
||||
<!-- You might want to roll out the known_hosts centrally. -->
|
||||
---
|
||||

|
||||
<style scoped>
|
||||
ul {
|
||||
font-size: smaller;
|
||||
}
|
||||
</style>
|
||||
To recap:
|
||||
- temp pub/priv keys used to establish connection & share the session secret
|
||||
- from this point on, all comms on the ssh session are protected by this session secret
|
||||
- ```known_hosts``` important to prevent man-in-the-middle attacks
|
||||
<!-- Right, that's the basic how. Let's get to some things that make your life so much easier, yet that are often misunderstood. -->
|
||||
|
||||
|
||||
<span style="color: darkgrey; font-size: 0.4em">Photo by <a href="https://unsplash.com/@awcreativeut?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Adam Winger</a> on <a href="https://unsplash.com/photos/girl-writing-on-the-ground-using-a-spray-an-GIFlfKX23rc?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></span>
|
||||
|
||||
---
|
||||
# Part 2
|
||||
### The Two Pillars
|
||||

|
||||
- Key based auth
|
||||
- ssh agent
|
||||
<!-- The most widely used yet often misunderstood features of SSH. This is why you are here.-->
|
||||
<span style="color: darkgrey; font-size: 0.4em">Photo by <a href="https://unsplash.com/@cajeo?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Cajeo Zhang</a> on <a href="https://unsplash.com/photos/gray-rock-formation-during-daytime-EbOAPSCwjnU?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></span>
|
||||
|
||||
---
|
||||
# Key-based authentication
|
||||
|
||||
- A private (secret, **only for you**) key
|
||||
- **never** give this to anyone else
|
||||
- **never** copy this to another machine
|
||||
- A public (everyone can have it) key
|
||||
- <small>can be generated from the private key</small>
|
||||
- typically, ```id_rsa``` and ```id_rsa.pub```
|
||||
- <small>or ```id_ed25519```, ```id_dsa```, ...</small>
|
||||
<!--
|
||||
One of the core failures of the whole SSH ecosystem is the default naming convention for private/public keys. Accidentally cat'ing your private key is way too easy.
|
||||
|
||||
rsa, dsa, ed25519 are different variants/types of encryption. When in doubt, use RSA.
|
||||
|
||||
(I would always go with ED25519 for modern deployments, though it might not work on systems that are older than 2020ish)
|
||||
|
||||
-->
|
||||
---
|
||||
## how to generate a key pair
|
||||
- ```ssh-keygen -t rsa -b 4096```
|
||||
- will create ```~/.ssh/id_rsa``` and ```~/.ssh/id_rsa.pub```
|
||||
- ```ssh-keygen -t ed25519```
|
||||
- →```id_ed25519```, essentially, it's ```id_$TYPE```
|
||||
- please, do set a passphrase for the key. I will explain how to make it not annoying.
|
||||
|
||||
<!-- Securing your private key with a passphrase (which just means "long password") is a good precaution, it means somebody that gets access to your private key cannot immediately use it. -->
|
||||
|
||||
---
|
||||
## and now? aka ```authorized_keys```
|
||||
<!--Okay, now you have your key, and you can give the public side of it to others. If others want to securely encrypt something that **only** you can decrypt, they use your **public** key to encrypt. You then use your **private** key to decrypt.-->
|
||||
You now put the **public** key into the ```~/.ssh/authorized_keys``` file of the user/host combination you want to have access to.
|
||||
|
||||
```
|
||||
# cat ~/.ssh/authorized_keys
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA6Gc/53b0ZBGL/ORF5hIa61hTPTAsrjnkxXl3wawsHT felix@home
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEx6jIZeHFxh1NDJOoHGQLg0ViqqFNKGd5ofTRvHb4Fh backuppc@backup
|
||||
```
|
||||
|
||||
<!-- In order to use this for authentication instead of a password, the SSH server will essentially encrypt something with your public key and ask you to send the decrypted text back (to prove that you are indeed in posession of the private key part) -->
|
||||
|
||||
<span style="color: orange; font-size: 0.5em">(Remember, do not give your private key to anyone. Never.)</span>
|
||||
<!--*READABLE* && pubkey → *CRYPTED* && privkey → *READABLE*-->
|
||||
|
||||
---
|
||||
## example login
|
||||
having added the contents of my ```~/.ssh/id_ed25519.pub``` file to the user ```root``` on my server ```db.example.com```, I can now do
|
||||
```
|
||||
ssh -i ~/.ssh/id_ed25519 root@db.example.com
|
||||
```
|
||||
My local SSH client will ask me for my passphrase (to unlock the private key into memory), then use the private key to authenticate me, allowing me to log in.
|
||||
|
||||
<!-- Yes, this feels identical to logging in with a password, except I was encouraged to make my passphrase longer and more annoying to type. Great job, you've made using ssh more annoying. -->
|
||||
|
||||
---
|
||||
|
||||
# SSH agent
|
||||
- Stores unlocked private keys in memory
|
||||
- only enter your passphrase when adding the key to the in-memory store
|
||||
- configurable lifetime
|
||||
- I would recommend 8-10 hours, so that during normal working hours you enter your passphrase once per day.
|
||||
- Painless passwordless logins!
|
||||
- can either manually add keys to it using ```ssh-add``` or set ```AddKeysToAgent yes``` in your ssh config
|
||||
<!-- Should probably more accurately be called the SSH private key cache. It's well integrated into openssh, and normal ssh connection attempts will try to use your local ssh agent automatically. -->
|
||||
<!-- On macos, you can use the system keychain to store the passphrase, where they will live together with all the other saved passwords, protected by a master password. It's ```UseKeychain yes
|
||||
``` in your .ssh/config, and I would recommend to use that if you're on a mac. -->
|
||||
<!-- On windows, putty has "pageant" to serve as private key cache, it works identically, though by default does not set a lifetime (you do need to re-enter passphrase after rebooting) -->
|
||||
|
||||
<!-- This is a must-have if you're serious about using key-based auth. You can get by with using keys without passphrase, but please don't, it carries a heavy price in terms of identity theft and potential damage to your reputation. As a sidenote, with more and more machines ending up in an MDM (mobile device management) "friendly rootkit" scenario, your private keys, passphrases and logins etc are essentially all compromised (to your MDM admins), making (digital) identity inside your company all but meaningless, but that is a topic for another talk... or hit me up later, I will talk at length about the problems I see with MDM :) -->
|
||||
|
||||
|
||||
---
|
||||
# Agent forwarding
|
||||
- Exposes your private key cache (the "agent") to the system you're connecting to
|
||||
- ```SSH_AUTH_SOCK``` environment variable
|
||||
```
|
||||
# echo $SSH_AUTH_SOCK
|
||||
/tmp/ssh-XXXXiA23DL/agent.1337770
|
||||
```
|
||||
- allows you to access your private keys from an intermediary system
|
||||
- but everyone with root rights on the intermediary can use your SSH_AUTH_SOCK!
|
||||
|
||||
<!-- you have essentially compromised your keys to every admin of the intermediary system. Be very, very careful where you agent forward to. Come visit my advanced SSH workshop to learn a better way.-->
|
||||
|
||||
---
|
||||

|
||||
# Finished
|
||||
<style scoped>
|
||||
ul {
|
||||
font-size: smaller;
|
||||
}
|
||||
</style>
|
||||
- keep your private key very private
|
||||
- be very careful with agent forwarding
|
||||
- be paranoid with ```known_hosts```
|
||||
- check out the manpage of the ssh client config: ```man ssh_config```
|
||||
- visit the advanced workshop
|
||||
<!-- -->
|
||||
|
||||
<span style="color: darkgrey; font-size: 0.4em">Photo by <a href="https://unsplash.com/@bboy_mocachino?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Jonatan David</a> on <a href="https://unsplash.com/photos/a-blurry-photo-of-a-street-with-a-stop-sign-K7MkzR7rBmM?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></span>
|
||||
|
||||
<!-- This covers what I consider the SSH 101 -->
|
||||
|
||||
---
|
||||
Teaser: Ich wollte eh auf der DENOG Workshop fuer ssh machen, gebe hier mal Teaser, Rest koennt ihr dann euch selber angucken, ...
|
||||
|
||||
|
||||
Praxis-Fails einbauen - neue hostkeys, passwort eingeben muessen, passphrase, ... jetzt muss ich meinen private key auf den jumphost kopieren, nein doch nicht, .... teaser-problem fuer proxyjump
|
||||
|
||||
optional proxyjump, falls ich zu schnell durchgehe bzw generell mal fragen, ob weiteres Interesse besteht
|
||||
|
||||
fuer lab: ein ssh-container-labyrinth, proxyjumps aussenrum und dann zum Schluss mit einem einzelnen ssh-kommando dateien aus der Mitte nach aussen... oder so.
|
||||
|
||||
---
|
||||
https://www.openssh.com/legacy.html
|
||||
KexAlgorithms: the key exchange methods that are used to generate per-connection keys
|
||||
HostkeyAlgorithms: the public key algorithms accepted for an SSH server to authenticate itself to an SSH client
|
||||
Ciphers: the ciphers to encrypt the connection
|
||||
MACs: the message authentication codes used to detect traffic modification
|
||||
`ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 user@legacyhost`
|
||||
`ssh -oHostKeyAlgorithms=+ssh-dss user@legacyhost`
|
||||