-
-
Save chrishoffman/c36593331df448c1fdff0405f818656f to your computer and use it in GitHub Desktop.
Example of Vault PKI (X509) backend issuing certificates to client and server, which then perform TLS mutual auth
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/tls" | |
"fmt" | |
"html" | |
"io/ioutil" | |
"log" | |
"net" | |
"net/http" | |
"time" | |
"github.com/hashicorp/vault/api" | |
"github.com/hashicorp/vault/helper/certutil" | |
) | |
const ( | |
pkiIssueToken string = "[insert token]" | |
vaultAddr string = "http://localhost:8200" | |
roleName string = "pki/issue/test" | |
) | |
func getTLSConfig() (*tls.Config, error) { | |
client, err := api.NewClient(&api.Config{ | |
Address: vaultAddr, | |
}) | |
if err != nil { | |
return nil, err | |
} | |
if client == nil { | |
return nil, fmt.Errorf("Returned client was nil") | |
} | |
client.SetToken(pkiIssueToken) | |
secret, err := client.Logical().Write(roleName, map[string]interface{}{ | |
"common_name": "localhost", | |
"ip_sans": "127.0.0.1", | |
"lease": "1h", | |
}) | |
if err != nil { | |
return nil, err | |
} | |
if secret == nil { | |
return nil, fmt.Errorf("Returned secret was nil") | |
} | |
parsedCertBundle, err := certutil.ParsePKIMap(secret.Data) | |
if err != nil { | |
return nil, fmt.Errorf("Error parsing secret: %s", err) | |
} | |
tlsConfig, err := parsedCertBundle.GetTLSConfig(certutil.TLSClient | certutil.TLSServer) | |
if err != nil { | |
return nil, fmt.Errorf("Could not get TLS config: %s", err) | |
} | |
return tlsConfig, nil | |
} | |
func runServer() { | |
tlsConfig, err := getTLSConfig() | |
if err != nil { | |
log.Printf("[Server] Encountered error getting tls config: %s", err) | |
return | |
} | |
tlsConfig.ServerName = "localhost" | |
tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven | |
ln, err := net.Listen("tcp", ":9182") | |
if err != nil { | |
log.Printf("[Server] Error listening: %s", err) | |
return | |
} | |
tlsListener := tls.NewListener(ln.(*net.TCPListener), tlsConfig) | |
log.Printf("[Server] Starting...") | |
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | |
switch len(r.TLS.VerifiedChains) { | |
case 0: | |
fmt.Fprintf(w, "Hello! You accesed %q without a client certificate", html.EscapeString(r.URL.Path)) | |
default: | |
fmt.Fprintf(w, "Hello! You accesed %q WITH a client certificate (good job!)", html.EscapeString(r.URL.Path)) | |
} | |
}) | |
srv := &http.Server{} | |
err = srv.Serve(tlsListener) | |
if err != nil { | |
log.Printf("[Server] Error serving: %s", err) | |
} | |
} | |
func runClient() { | |
tlsConfig, err := getTLSConfig() | |
if err != nil { | |
log.Printf("[Client] Encountered error getting tls certificate: %s", err) | |
return | |
} | |
log.Printf("[Client] Starting...") | |
tr := &http.Transport{TLSClientConfig: tlsConfig} | |
client := &http.Client{Transport: tr} | |
for { | |
resp, err := client.Get("https://localhost:9182/") | |
if err == nil { | |
body, err := ioutil.ReadAll(resp.Body) | |
if err != nil { | |
log.Printf("[Client] Error reading response body: %s", err) | |
} else { | |
log.Printf("[Client] Got %s", string(body)) | |
} | |
resp.Body.Close() | |
return | |
} | |
time.Sleep(500 * time.Millisecond) | |
} | |
} | |
func main() { | |
go runClient() | |
runServer() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment