Skip to content

Commit

Permalink
feat(ssh): add signed ssh certificates lab
Browse files Browse the repository at this point in the history
  • Loading branch information
fxkk committed Jan 12, 2024
1 parent 98163dd commit 86be179
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 0 deletions.
Binary file added docs/assets/ssh_sign.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
105 changes: 105 additions & 0 deletions docs/ssh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# SSH secrets engine

![img](assets/shh_sign.png)
> https://www.hashicorp.com/blog/managing-ssh-access-at-scale-with-hashicorp-vault

The idea of the ssh secret engine is to supplement the classic ssh public key authentication with a signing workflow.

This means that public keys are no longer entered in the authorized keys files on individual hosts. Instead, all hosts trust the vault ssh ca and therefore keys signed by it. The contexts in which the signed key are valid is specified in the signature.

To log on to a server, not only the private key but also the corresponding public key signed by the vault ca must be provided.

The numbers in the diagram represent the following steps:

- User creates a personal SSH key pair.
- User authenticates to Vault with their Identity Provider (IDP) credentials.
- Once authenticated, the user sends their SSH public key to Vault for signing.
- Vault signs the SSH key and return the SSH certificate to the user.
- User initiates SSH connection using the SSH certificate.
- Host verifies the client SSH certificate is signed by the trusted SSH CA and allows connection.

[HashiCorp Blog](https://www.hashicorp.com/blog/managing-ssh-access-at-scale-with-hashicorp-vault)


## Requirements
You can enable this lab by setting:

```yaml
# terraform.tfvars
ssh = {
enabled = true
}
```

You then can bootstrap the cluster using `make bootstrap`

## Overview
The following resources will be created:

1. A Ubuntu Container will be deployed
2. The ssh secret engine will be enabled
3. A ssh signing ca will be created
4. A ssh secret backend role that will allow you to login as the ubuntu user

## Walkthrough

The SSH signing ca has been configured under the `ssh-client-signer` path.

```bash
$ vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
ssh-client-signer/ ssh ssh_002866eb n/a

$ vault read ssh-client-signer/config/ca
Key Value
--- -----
public_key ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDjcpfjEV7fqCj6I14a6oGrfy6M9Fgi5ZQj7brbocNXG4w4GkZkrO5g93fec+5vcn6eoJYG4n==
```

A ssh signer role has been created.

```bash
$vault read ssh-client-signer/roles/ubuntu
Key Value
--- -----
algorithm_signer default
allow_bare_domains false
allow_host_certificates false
allow_subdomains false
allow_user_certificates true
allow_user_key_ids false
allowed_critical_options n/a
allowed_domains n/a
allowed_domains_template false
allowed_extensions n/a
allowed_user_key_lengths map[]
allowed_users ubuntu
allowed_users_template false
default_critical_options map[]
default_extensions map[permit-pty:]
default_extensions_template false
default_user ubuntu
default_user_template false
key_id_format n/a
key_type ca
max_ttl 0s
not_before_duration 30s
ttl
```

To log in to the ubuntu container you need to sign you public key.

```bash
$ vault write -field=signed_key ssh-client-signer/sign/ubuntu public_key=@$HOME/.ssh/id_rsa.pub >| signed-cert.pub
```

Query the ip of the ubuntu container and use the signed public key and your private key to connect.

```bash
export UBUNTU_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ubuntu
ssh -i signed-cert.pub -i ~/.ssh/id_rsa ubuntu@$UBUNTU_IP
```
8 changes: 8 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,11 @@ module "cm" {

depends_on = [module.vault_k8s]
}

module "ssh" {
count = var.ssh.enabled ? 1 : 0

source = "./vault-ssh/terraform"

depends_on = [module.vault]
}
5 changes: 5 additions & 0 deletions terraform.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,8 @@ kubernetes = {
# enable vault agent injector
vault_agent_injector = true
}


ssh = {
enabled = false
}
6 changes: 6 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ variable "kubernetes" {
cert_manager = optional(bool, true)
})
}

variable "ssh" {
type = object({
enabled = optional(bool, true)
})
}
14 changes: 14 additions & 0 deletions vault-ssh/files/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#/usr/bin/sh

apt-get update
apt install -y openssh-server curl

mkdir /var/run/sshd
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
curl -k -o /etc/ssh/trusted-user-ca-keys.pem https://haproxy/v1/ssh-client-signer/public_key
echo "TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem" >> /etc/ssh/sshd_config

useradd -m ubuntu -s /bin/bash


/usr/sbin/sshd -D
55 changes: 55 additions & 0 deletions vault-ssh/terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

data "docker_network" "vault" {
name = "vault"
}

resource "docker_container" "ubuntu" {
name = "ubuntu"
image = "ubuntu:latest"

command = ["/usr/bin/sh", "/files/init.sh"]

volumes {
host_path = abspath("${path.root}/vault-tls/output")
container_path = "/opt/tls/"
read_only = true
}

volumes {
host_path = abspath("${path.root}/vault-ssh/files")
container_path = "/files"
read_only = true
}

networks_advanced {
name = data.docker_network.vault.name
}

lifecycle {
ignore_changes = all
}

depends_on = [vault_ssh_secret_backend_ca.this]
}

resource "vault_mount" "ssh" {
type = "ssh"
path = "ssh-client-signer"
}

resource "vault_ssh_secret_backend_ca" "this" {
backend = vault_mount.ssh.path
generate_signing_key = true
}

resource "vault_ssh_secret_backend_role" "ubuntu" {
name = "ubuntu"
backend = vault_mount.ssh.path
key_type = "ca"
allow_user_certificates = true
allowed_users = "ubuntu"
default_user = "ubuntu"
default_extensions = {
"permit-pty" : ""
}
}
15 changes: 15 additions & 0 deletions vault-ssh/terraform/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
terraform {
required_version = ">= 1.6.0"

required_providers {
vault = {
source = "hashicorp/vault"
version = "3.20.1"
}
docker = {
source = "kreuzwerker/docker"
version = "3.0.2"
}
}
}

0 comments on commit 86be179

Please sign in to comment.