Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpweber/42462c8409793ccd19585bacbdcb7270 to your computer and use it in GitHub Desktop.
Save jpweber/42462c8409793ccd19585bacbdcb7270 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
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