Skip to content

Commit 22b8941

Browse files
author
Brian McCallister
committed
initial playing around
1 parent c7faae6 commit 22b8941

20 files changed

+239
-1
lines changed

README.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,45 @@
1-
# epithet
1+
# epithet makes secure ssh certificate AAA easy
2+
3+
## Authentication
4+
5+
Short lived SSH certs.
6+
7+
What is short-live default? 10 minutes, 1 hour? How do we arrive at a sound number rather than a "this sounds good"?
8+
9+
How do we authenticate to the CA service? This seems like it should be pluggable (SAML, OAuth, OpenID)
10+
11+
## Authorization
12+
13+
By principals-as-groups rather than principals-as-people.
14+
15+
How much should we care about individuals vs groups? My tendency is to steer to principal being the group not the individual, then manage who is in what group in the cert generating machinery.
16+
17+
## Accounting (Auditing)
18+
19+
Use cert ID to know who did what.
20+
21+
[Facebook style](https://engineering.fb.com/security/scalable-and-secure-access-with-ssh/) ssh handling seems to take this approach.
22+
23+
# Login Mechanism
24+
25+
How do we make sure ssh sends the right cert?
26+
27+
We have a couple options, either one implies we authenticate to a local agent, which is granted credentials to communicate with the CA to obtain short lived certificates. We must never *trust* the agent to do more than obtain certs on behalf of the person whom it has credentials for -- ie, it must never get the CA private key.
28+
29+
## Option: custom ssh-agent and `IdentityAgent` directives on host patterns
30+
31+
No interest in replacing default openssh ssh-agent, but you can specify a different one for a host block in config. I don't know if there is a mechanism to launch it if missing, but worst case we need to start a daemon.
32+
33+
We then need to have a communication channel between that agent and the CA which we trust. It seems like starting the agent explicitely and doing an auth dance (CLI saml with okta, pop a web browser, etc) that tells the CA to trust the agent can work. Implies we could use short lived TLS certs for Agent -> CA, though this may be overthinking it.
34+
35+
## Option: daemon generate cert file
36+
37+
Instead of asking the agent for the cert, just update contents of `~/.ssh/` to replace a named certificate. A drawback here is that we don't know when it is being used, so refreshing it will need to be out of band.
38+
39+
This feels like it would be faster to start with, but more limited than having an agent proper.
40+
41+
42+
# "Installation"
43+
44+
Seems critical that an installation needs to run its own CA for security, so we need to make CA setup process as one-click as we can. For v1, seems fine to assume AWS will host, but am sure by v7 we will need to not care, so don't make decisions that lock us in to a single infra, but don't worry about supporting multiple infrastructures yet.
45+

agent/main.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net"
6+
7+
"golang.org/x/crypto/ssh"
8+
"golang.org/x/crypto/ssh/agent"
9+
)
10+
11+
func main() {
12+
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pubCert))
13+
if err != nil {
14+
panic(err)
15+
}
16+
cert, ok := pk.(*ssh.Certificate)
17+
if !ok {
18+
panic("not a certificate!")
19+
}
20+
21+
priv, err := ssh.ParseRawPrivateKey([]byte(privateKey))
22+
if err != nil {
23+
panic(err)
24+
}
25+
26+
keyring := agent.NewKeyring()
27+
keyring.Add(agent.AddedKey{
28+
PrivateKey: priv,
29+
Certificate: cert,
30+
})
31+
32+
path := "/tmp/epithet-agent"
33+
34+
sock, err := net.Listen("unix", path)
35+
if err != nil {
36+
panic(err)
37+
}
38+
39+
fmt.Println("export SSH_AUTH_SOCK=/tmp/epithet-agent")
40+
for {
41+
conn, err := sock.Accept()
42+
if err != nil {
43+
panic(err)
44+
}
45+
go func() {
46+
err := agent.ServeAgent(keyring, conn)
47+
if err != nil {
48+
panic(err)
49+
}
50+
}()
51+
}
52+
}
53+
54+
const privateKey = `-----BEGIN OPENSSH PRIVATE KEY-----
55+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
56+
QyNTUxOQAAACD+94OTJVooGNj9LO4lPwobX9zIvisccuNeTpBMsQO+UgAAAJjcBY813AWP
57+
NQAAAAtzc2gtZWQyNTUxOQAAACD+94OTJVooGNj9LO4lPwobX9zIvisccuNeTpBMsQO+Ug
58+
AAAEC6GR1iGMhzhphbnsAIN44Wpn8AZzAQTWh/gdHaKzfOg/73g5MlWigY2P0s7iU/Chtf
59+
3Mi+Kxxy415OkEyxA75SAAAAD2JyaWFubW5Ac2N1ZmZpbgECAwQFBg==
60+
-----END OPENSSH PRIVATE KEY-----`
61+
62+
const pubCert = `[email protected] AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAID4AIPoWH60yQ3Ay6V9oYBBALFVszirLToisufG6hGaLAAAAIP73g5MlWigY2P0s7iU/Chtf3Mi+Kxxy415OkEyxA75SAAAAAAAAAAAAAAABAAAABmJyaWFubQAAAAoAAAAGYnJpYW5tAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDNH7zWoDN/0GHOqMq8E4l0xehxI4bqcqp4FmjMoGp1gb1VYl+G/KWoRufzamCvVvX37oGfTlIi/0wW/mCFPtVv9Dg6nWGVRz6rECv4hjF4TcxgXIXbVLw70Lwy0FNhc9bX13D+4Z8UkaP94c0s79nbtfW7w82jvnCXwWYh9odr+PX9tSZOCJvWgoGd0/pMbyLp/7EapGByu+fxqx4Xyb89RVtCpBBZrZ7xOqPV5wD5BjHfrCREqcdeV8jzzQkxDUclPjbFga4WWUMEFz3lr8b14yPl0m5ANCRFz2RX7jp8xKiL8gz7V0K37ZX5vHaGgaDHgQbmRvq7BkaGWRYELyzJAAABDwAAAAdzc2gtcnNhAAABALpCd/eBkQig/ap5wCJQEfx9xMhNMPa0Fn4+b2F80dHBKly9xZAM68h/sKIrJZe17xspFbe0gDNs7RkFtBnK6iLG5VZSNIzwsxGJ63J/w1DMrz1t1gJQNCDfzpznNJOc4MhcbF6HdF+kYA11DIN/lST1Th80l7EM9Q4NVChA5J2bDiSUso5oMN+RkUJRiCBjc6UG9BiJt3c3B2cUuvjSEtU/jRrR6sCH+klICOUSsscOToiFxjtsL4wmogMD+TS9e7CpgJBX8cxZP1pZ2bY5qik27llPS1YAtroEbE4OliqZQ35wLqHsmMYYg5LDTFhd+HOu1fGSaemeh92CaGvOyAQ= brianmn@scuffin`

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/brianm/epithet
2+
3+
go 1.13
4+
5+
require (
6+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
7+
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect
8+
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
3+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
4+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
6+
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
7+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
8+
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
9+
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

play/PLAY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```
2+
sshd -c cert_file -d -f ./config_file -h ./host_key_file -p $PORT
3+
```

play/ca/ca

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
3+
NhAAAAAwEAAQAAAQEAzR+81qAzf9BhzqjKvBOJdMXocSOG6nKqeBZozKBqdYG9VWJfhvyl
4+
qEbn82pgr1b19+6Bn05SIv9MFv5ghT7Vb/Q4Op1hlUc+qxAr+IYxeE3MYFyF21S8O9C8Mt
5+
BTYXPW19dw/uGfFJGj/eHNLO/Z27X1u8PNo75wl8FmIfaHa/j1/bUmTgib1oKBndP6TG8i
6+
6f+xGqRgcrvn8aseF8m/PUVbQqQQWa2e8Tqj1ecA+QYx36wkRKnHXlfI880JMQ1HJT42xY
7+
GuFllDBBc95a/G9eMj5dJuQDQkRc9kV+46fMSoi/IM+1dCt+2V+bx2hoGgx4EG5kb6uwZG
8+
hlkWBC8syQAAA8DxizNB8YszQQAAAAdzc2gtcnNhAAABAQDNH7zWoDN/0GHOqMq8E4l0xe
9+
hxI4bqcqp4FmjMoGp1gb1VYl+G/KWoRufzamCvVvX37oGfTlIi/0wW/mCFPtVv9Dg6nWGV
10+
Rz6rECv4hjF4TcxgXIXbVLw70Lwy0FNhc9bX13D+4Z8UkaP94c0s79nbtfW7w82jvnCXwW
11+
Yh9odr+PX9tSZOCJvWgoGd0/pMbyLp/7EapGByu+fxqx4Xyb89RVtCpBBZrZ7xOqPV5wD5
12+
BjHfrCREqcdeV8jzzQkxDUclPjbFga4WWUMEFz3lr8b14yPl0m5ANCRFz2RX7jp8xKiL8g
13+
z7V0K37ZX5vHaGgaDHgQbmRvq7BkaGWRYELyzJAAAAAwEAAQAAAQEAx28PJEG4MJIDNnHI
14+
Q1pfb8in+bCIEVSRR5bKKAHj4AHXerfdlxn3WoguJu2LuY68MWWUY7Y7h8leSpDieUqhLG
15+
tvbBXudbxCQwHDLqwSVxyVFC+A+cIGDcYh5OnF199PyKWwODBXgiEkJ8ituv4sfEEK/Zcf
16+
Tg/v2qxvx5+xBRjZOMclfhFvtv+QxsE+yFH9+KZvrtv0GsEHTnCD1FsY1Vh6vZhBBjFNFo
17+
JtKw5KIiXGdmMv9s6cUT4DClG31M2QnvbppQhLrxxdLAGTB0Dr7ldtBZdauhKhPo1TaJMg
18+
3EQZ7IYoyBeCedOagAKb0GW68FW0Tmy73HaRfU8dZgnaDQAAAIAncC8GP72UgX7zxJ19Go
19+
/tpmKyQvtrOjtmZAja0/y+bePYwHllvTfPLEo5NOeiLv8fDTTIPETUMmihywstyU2TPbWq
20+
pgRjXCv36QGYlviKfjja1uIwd9KLJRKavI3kp+0uz6ZJFxrez0i7GCR0Tu2rX+RGrjLj2V
21+
mY+eCroW+y5AAAAIEA5+Hl9hU2Sbx8j6Ohgeyn9eFfVTafRttMg2wMQVNW0MzMj0DibSKT
22+
Fi55TwSANSXMQ/uL3eW6ZcHcxKQCxT2KzTz7QiR3qE2uad9EQx3N6XWKxDoPlDgrlUktcH
23+
nYy4rmJe7HVL7FpBuFUxsfrlgVclrxClA/lZq8mP9CutlZBYcAAACBAOJ1XnwElJpDxwWY
24+
HEM250mpK26m4oxkjBMIx/lLC1DST+vMU2k/N801xi6Rb1MravliiuK0jHZlJO4DL816GV
25+
lTe2/oE0W4DNt/J1ypylVLVL2E2EKqQqHbYmXQ87EFdp8OanAu6F29pRdKstTbYkGk6lET
26+
lYB3IqmowLJ7ac8vAAAAB3VzZXItY2EBAgM=
27+
-----END OPENSSH PRIVATE KEY-----

play/ca/ca.pub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNH7zWoDN/0GHOqMq8E4l0xehxI4bqcqp4FmjMoGp1gb1VYl+G/KWoRufzamCvVvX37oGfTlIi/0wW/mCFPtVv9Dg6nWGVRz6rECv4hjF4TcxgXIXbVLw70Lwy0FNhc9bX13D+4Z8UkaP94c0s79nbtfW7w82jvnCXwWYh9odr+PX9tSZOCJvWgoGd0/pMbyLp/7EapGByu+fxqx4Xyb89RVtCpBBZrZ7xOqPV5wD5BjHfrCREqcdeV8jzzQkxDUclPjbFga4WWUMEFz3lr8b14yPl0m5ANCRFz2RX7jp8xKiL8gz7V0K37ZX5vHaGgaDHgQbmRvq7BkaGWRYELyzJ user-ca

play/server/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM eg_sshd:1
2+
3+
RUN mkdir /etc/ssh/auth_principals
4+
RUN chmod 0755 /etc/ssh/auth_principals
5+
6+
COPY ca.pub /etc/ssh/ca.pub
7+
COPY sshd_config /etc/ssh/sshd_config
8+
COPY auth_principals/* /etc/ssh/auth_principals/
9+
RUN chmod 0644 /etc/ssh/sshd_config /etc/ssh/ca.pub
10+
11+
EXPOSE 22
12+
CMD ["/usr/sbin/sshd", "-d"]

play/server/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
TMP := "/srv/epithet-server"
2+
3+
.PHONY: server
4+
server: prep
5+
sudo /usr/sbin/sshd -f $(TMP)/sshd_config -d
6+
7+
prep:
8+
sudo rm -rf $(TMP)
9+
sudo mkdir -p $(TMP)
10+
sudo chmod 0700 $(TMP)
11+
sudo cp -r * $(TMP)/
12+
sudo find $(TMP) -type d -exec chmod 0700 {} \;
13+
sudo find $(TMP) -type f -exec chmod 0700 {} \;

play/server/auth_principals/root

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
brianm

0 commit comments

Comments
 (0)