Last active
May 20, 2022 13:29
-
-
Save jefferai/e2bebc3bb97fed521666 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() | |
} |
The certutil
package seems to have been moved to github.com/hashicorp/vault/sdk/helper/certutil
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a great sample. Thanks!