From fdb4fb3b6c2d82a0dcf6d29d5183c3cb031b86f2 Mon Sep 17 00:00:00 2001 From: Justin Patriquin Date: Fri, 25 Nov 2022 15:31:37 -0400 Subject: [PATCH] Add vault example with and without TLS Also adds the ability to customize the name of the Dockerfile to read. This is helpful if you have multiple docker files in the same directory. --- .github/workflows/release.yaml | 3 +- examples/vault/Dockerfile | 14 ++++ examples/vault/Dockerfile.tls | 15 ++++ examples/vault/README.md | 124 +++++++++++++++++++++++++++++++++ examples/vault/app-tls.sh | 3 + examples/vault/app.sh | 3 + examples/vault/config-tls.hcl | 14 ++++ examples/vault/config.hcl | 13 ++++ examples/vault/run.sh | 8 +++ src/bin/nitrogen.rs | 24 +++++-- src/commands/build.rs | 11 ++- src/commands/deploy.rs | 2 +- 12 files changed, 223 insertions(+), 11 deletions(-) create mode 100644 examples/vault/Dockerfile create mode 100644 examples/vault/Dockerfile.tls create mode 100644 examples/vault/README.md create mode 100644 examples/vault/app-tls.sh create mode 100644 examples/vault/app.sh create mode 100644 examples/vault/config-tls.hcl create mode 100644 examples/vault/config.hcl create mode 100644 examples/vault/run.sh diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7b6fc82..4e9dfe9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -37,8 +37,7 @@ jobs: run: | cargo build --release - name: tar - run: | - tar --directory=target/release -cf archive.tar.gz nitrogen.exe + run: tar --directory=target/release -cf archive.tar.gz nitrogen.exe - name: upload run: | $id = gh api -H "Accept: application/vnd.github+json" /repos/capeprivacy/nitrogen/releases/tags/${{ github.ref_name }} --jq .id diff --git a/examples/vault/Dockerfile b/examples/vault/Dockerfile new file mode 100644 index 0000000..867ea1f --- /dev/null +++ b/examples/vault/Dockerfile @@ -0,0 +1,14 @@ +FROM vault:latest + + +RUN apk --no-cache add socat=1.7.4.1-r1 + +COPY config.hcl config.hcl + +COPY run.sh ./ +RUN ["chmod", "+x", "./run.sh"] + +COPY app.sh ./ +RUN ["chmod", "+x", "./app.sh"] + +CMD ["/bin/sh", "/run.sh"] diff --git a/examples/vault/Dockerfile.tls b/examples/vault/Dockerfile.tls new file mode 100644 index 0000000..fb4e5c0 --- /dev/null +++ b/examples/vault/Dockerfile.tls @@ -0,0 +1,15 @@ +FROM vault:latest + + +RUN apk --no-cache add socat=1.7.4.1-r1 + +COPY config-tls.hcl config-tls.hcl +COPY vault.key vault.pem ./ + +COPY run.sh ./ +RUN ["chmod", "+x", "./run.sh"] + +COPY app-tls.sh ./app.sh +RUN ["chmod", "+x", "./app.sh"] + +CMD ["/bin/sh", "/run.sh"] diff --git a/examples/vault/README.md b/examples/vault/README.md new file mode 100644 index 0000000..0346483 --- /dev/null +++ b/examples/vault/README.md @@ -0,0 +1,124 @@ +# Vault Example + +## Requirements + +- vault CLI (see [here](https://developer.hashicorp.com/vault/docs/install) for installation instructions) + +## Deploy Vault + +``` +$ nitrogen setup vault-nitro ~/.ssh/id_rsa.pub +``` + +``` +$ nitrogen build examples/vault +``` + +``` +$ nitrogen deploy vault-nitro ~/.ssh/id_rsa +``` + +After the last command you should see something like: + +``` +... +2022-11-24T19:23:19.595376Z INFO nitrogen::commands::deploy: EIF is now running public_dns="ec2-54-159-199-57.compute-1.amazonaws.com" +2022-11-24T19:23:19.595512Z INFO nitrogen::commands::deploy: Check enclave status... +2022-11-24T19:23:20.159233Z INFO nitrogen::commands::deploy: Enclave up and running! +``` + +## Setup Vault + +Here we've deployed Vault in production mode so it takes a few more steps to fully set up Vault. + +First, set the address of the ec2 instance: + +``` +$ export VAULT_ADDR="ec2-54-159-199-57.compute-1.amazonaws.com" +``` + +Next initialize vault: + +``` +$ vault operator init +``` + +Should see some output like: + +``` +Unseal Key 1: J6jRd1lZ7eU+wmBmtE4OsmymVtWfPmpGnh7z/o4e68JG +Unseal Key 2: cLZnWKAt2KxSpsMxNAOZ05Pcv1XmxFugcrzh3fNp+GCw +Unseal Key 3: quW9NrKUdrLcpYCnHRqUORXH+VjX9O8QwHafQETtVxcU +Unseal Key 4: ZI9pTMq7KEy7e2zC+AJx5iSANTBQA4ts0UxJeh7EyEqS +Unseal Key 5: F5lI1mjyR7h24lDtY95uBLLRs+mupcTvJBRl+aDtSd4a + +Initial Root Token: hvs.FDnNk0XLP7jv2g18UnMkN3mi + +Vault initialized with 5 key shares and a key threshold of 3. Please securely +distribute the key shares printed above. When the Vault is re-sealed, +restarted, or stopped, you must supply at least 3 of these keys to unseal it +before it can start servicing requests. + +Vault does not store the generated root key. Without at least 3 keys to +reconstruct the root key, Vault will remain permanently sealed! + +It is possible to generate new unseal keys, provided you have a quorum of +existing unseal keys shares. See "vault operator rekey" for more information. +``` + +Then for 3 of the key shares call the following: + +``` +$ vault operator unseal +``` + +Finally log in with the root token: + +``` +$ vault login +``` + +## Store Keys + +To store keys in production mode we must first set up a secrets engine: + +``` +$ vault secrets enable kv +``` + +And then we can store and retrieve secrets: + +``` +$ vault kv put -mount=kv sec foo=bar +``` + +``` +$ vault kv get -mount=kev sec +``` + +## TLS + +**Note: reading the [nginx tls example](../nginx-tls/README.md) could be helpful for some more background** + +With some additional setup we can enable TLS. + +First, generate the certificate and key with `mkcert`: + +``` +$ mkcert -cert-file vault.pem -key-file vault.key +$ cp vault.pem vault.key examples/vault +``` + +``` +$ nitrogen build examples/vault -d Dockerfile.tls +``` + +``` +$ nitrogen deploy vault-nitro ~/.ssh/id_rsa +``` + +``` +$ export VAULT_ADDR="https://ec2-54-159-199-57.compute-1.amazonaws.com" +``` + +Then you can follow the rest of the sets from above but this is using TLS! diff --git a/examples/vault/app-tls.sh b/examples/vault/app-tls.sh new file mode 100644 index 0000000..f1b1ff5 --- /dev/null +++ b/examples/vault/app-tls.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +vault server -config=config-tls.hcl diff --git a/examples/vault/app.sh b/examples/vault/app.sh new file mode 100644 index 0000000..ecd854a --- /dev/null +++ b/examples/vault/app.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +vault server -config=config.hcl diff --git a/examples/vault/config-tls.hcl b/examples/vault/config-tls.hcl new file mode 100644 index 0000000..cde64d8 --- /dev/null +++ b/examples/vault/config-tls.hcl @@ -0,0 +1,14 @@ +backend "file" { + path = "/vault/file" + default_lease_ttl = "168h" + max_lease_ttl = "720h" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_cert_file = "vault.pem" + tls_key_file = "vault.key" +} + +api_addr = "http://0.0.0.0:8200" +cluster_addr = "https://0.0.0.0:8201" diff --git a/examples/vault/config.hcl b/examples/vault/config.hcl new file mode 100644 index 0000000..559eeb2 --- /dev/null +++ b/examples/vault/config.hcl @@ -0,0 +1,13 @@ +backend "file" { + path = "/vault/file" + default_lease_ttl = "168h" + max_lease_ttl = "720h" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = "true" +} + +api_addr = "http://0.0.0.0:8200" +cluster_addr = "https://0.0.0.0:8201" diff --git a/examples/vault/run.sh b/examples/vault/run.sh new file mode 100644 index 0000000..2110aa5 --- /dev/null +++ b/examples/vault/run.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +ip addr add 127.0.0.1/32 dev lo +ip link set dev lo up + +socat vsock-listen:5000,reuseaddr,fork tcp-connect:127.0.0.1:8200 & + +sh ./app.sh diff --git a/src/bin/nitrogen.rs b/src/bin/nitrogen.rs index 0e7b91f..ecd4e93 100644 --- a/src/bin/nitrogen.rs +++ b/src/bin/nitrogen.rs @@ -52,8 +52,13 @@ enum Commands { Build { /// Dockerfile directory dockerfile_dir: String, + + /// Output EIF location + #[arg(short, long, default_value_t = String::from("Dockerfile"))] + dockerfile_name: String, + /// Output EIF location - #[arg(short, long, default_value_t = String::from("./nitrogen.eif"))] + #[arg(short, long, default_value_t = String::from("nitrogen.eif"))] eif: String, }, @@ -62,7 +67,7 @@ enum Commands { /// Name of a Nitrogen-generated CloudFormation stack name: String, /// Filepath to EIF - #[arg(short, long, default_value_t = String::from("./nitrogen.eif"))] + #[arg(short, long, default_value_t = String::from("nitrogen.eif"))] eif: String, /// Filepath to SSH key for the instance ssh_key: String, @@ -164,10 +169,14 @@ async fn main() -> Result<(), Error> { } Commands::Build { dockerfile_dir, + dockerfile_name, eif, } => { - info!(dockerfile_dir, "Building EIF from dockerfile."); - let out = build(&dockerfile_dir, &eif).await?; + info!( + dockerfile_dir, + dockerfile_name, "Building EIF from dockerfile." + ); + let out = build(&dockerfile_dir, &dockerfile_name, &eif).await?; debug!(docker_output=?out, "Docker output:"); Ok(()) } @@ -258,7 +267,12 @@ async fn main() -> Result<(), Error> { // TODO should save this somewhere else than their current directory let eif_path = &format!("{}.eif", service); - build(&proj_dir.to_str().unwrap().to_string(), eif_path).await?; + build( + &proj_dir.to_str().unwrap().to_string(), + &"Dockerfile".to_string(), + eif_path, + ) + .await?; info!("Sleeping for 20s to give ec2 instance a chance to boot..."); tokio::time::sleep(Duration::from_secs(20)).await; diff --git a/src/commands/build.rs b/src/commands/build.rs index 2297731..b085e57 100644 --- a/src/commands/build.rs +++ b/src/commands/build.rs @@ -7,10 +7,14 @@ use tokio::process::Command; use tracing::{info, instrument}; #[instrument(level = "debug")] -pub async fn build(dockerfile_dir: &String, eif_name: &String) -> Result { +pub async fn build( + dockerfile_dir: &String, + dockerfile_name: &String, + eif_name: &String, +) -> Result { let dockerdir = PathBuf::from(dockerfile_dir); let mut dockerfile_path = PathBuf::from(dockerfile_dir); - dockerfile_path.push("Dockerfile"); + dockerfile_path.push(dockerfile_name); let out = Command::new("docker") .args([ @@ -61,7 +65,8 @@ pub async fn build(dockerfile_dir: &String, eif_name: &String) -> Result Result } fn check_enclave_status(ssh_key: &str, url: &str) -> Result<(), Error> { - info!("Check enclave status..."); + info!("Checking enclave status..."); match describe_enclave(ssh_key, url)?.get("State") { // According to the docs, the state is either "running" or "terminating"