This commit is contained in:
2023-04-02 12:07:58 +10:00
parent 2554c7f4ca
commit b45e276df5
4 changed files with 286 additions and 4 deletions

30
cert.pem Normal file
View File

@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFJzCCAw+gAwIBAgIQIVjBMPostxK1MlusUI+2PzANBgkqhkiG9w0BAQsFADAP
MQ0wCwYDVQQKEwREVE1TMB4XDTIzMDQwMjAxNDYxOVoXDTI0MDQwMTAxNDYxOVow
DzENMAsGA1UEChMERFRNUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
ALux7Yv5ckCP26S4DVxAqLp/ggCKOhqUxRqp5+59zTk1QcqbTeO/L3pC/4tNRRze
y6vEIeOcUKGt7DVDOFNc7n96WFxLdjIowatuetYestPriSGgqWUSABLUUC7gP5rU
wjf5MHoiq9JKJYv158goCOnNZerEMz5ApchlpSnLfeFfmEsYlcwLfTDL03wsUAug
HGjD0XqKR4CxaL1C8QUbkteY4j+OODMUnvzFXMRSajbN92mA5ROKibN4/cOyb6z7
66Jabdbcyj3obB6En1W8jCb1cofI/Dh8ZqtkSHRTTeosTHgm9XuLMwHPkQ2wOZHU
kudC4JvZsAy3aCl+14q3eaRUEPamd9Yg4mfB7VmrezDhGPRRX6kNGk4l2H8Pp/Fw
78UVhWNb/fPKsbXq+Zo7AH3oQrOa9Oc8+7/o+9wJEQu/tLj9bYSqUx9wIQfG0Lpy
J6CDFqGaxdcU9r4SFT45x411cBovcX8I888KE9E01W/kBBcaT0zjwTG+QfmDCyD1
6Yc5hvy2CKU6t0X/+BPCsyoVNp1/kva5JOGL38F7K0wlwoKMpT1jO4Ulsgejohmx
lW5Eoldhoc9NBS6ZBZ+m/rh34CWcFdNi+KzvGmL5KCGbzDXo1zyJLW+n968m5c16
DWsCRNX0UJC1841mCwb+W4TYs/2/19wZPFx0tLTx9C5PAgMBAAGjfzB9MA4GA1Ud
DwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/
MB0GA1UdDgQWBBTolBa+8La6LG3PK8Jh1bfRJY2yMjAmBgNVHREEHzAdgg9uYXRo
bWJwMTQubG9jYWyHBAoAAYGHBAoAAXswDQYJKoZIhvcNAQELBQADggIBALdb55i4
vEpltZ41CThTHN2+wLFAMrQPtRH0LeLaiikcn+BSt0TkOFIPfaAie0iYmYnEw1eb
0jw9Hu1avc7GIVaTiOFr9M7A/9VVltWqE/Ic5GH81XjjQJErjHAyULR/XO6CaPcj
ekMnDrTrfRdsie9DJHxXWLUowZwkinVDpCMeZFw6lLVYLpdx+nl+ouyEZSKGtDAh
mqSzqD0fw8aCwcbumfz7jY9US0LfPWUhjEyB200IsPU6fe9YtEyForH9wiRN1Y+p
q5gtPCYBBhopskLAnpA/hjYfpeN917yVHcWNDw8YaC4QKP+AmBC1gPyGnpTpBbzH
XT/IcMi3C7xvvKuTtacGRS5RoHOtBGDO/0PaW+IFrR9R89N8JhYgPA+fysPJ+fJn
YOTWW+n2Oc6QULv7pqCqfkQQ+TeQZHl9mZaHYzIvXGS2Fpo282EKCztzxrJJYZ9a
us7GL75UCNyNQDNii/AaSr3gA8CbKEaa3uDccv4+gxY137seF6qWakqLBm3Q4j6M
+nRb5++DVyPz8CpE9i2HkId+wwT3U6PiE7uFcJK+wpvpJmrqzcm3tHVBFe0Hp8YF
ykGZsMdaAkhIH1VtYggi26AIwe9vhtzb48LYLABYJ2blYXHsf/Md5MPhG8HFM9LR
iCNA98wWcCweUk1NpB6eYqTMbI9Qj4cYZ1MS
-----END CERTIFICATE-----

52
key.pem Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
YOtHX+6Qh2feqdNVUqFtlMCuk5iZUel9
-----END PRIVATE KEY-----

51
main.go
View File

@@ -4,9 +4,13 @@ import (
"ccsecrets/controllers"
"ccsecrets/middlewares"
"ccsecrets/models"
"ccsecrets/utils"
"context"
"crypto/tls"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
@@ -26,12 +30,51 @@ func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
//time.Sleep(10 * time.Second)
c.String(http.StatusOK, "Welcome Gin Server")
c.String(http.StatusOK, "Hello World.")
})
// Set some options for TLS
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
PreferServerCipherSuites: true,
InsecureSkipVerify: true,
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
}
// Determine bind IP
bindIP := os.Getenv("BIND_IP")
if bindIP == "" {
bindIP = utils.GetOutboundIP().String()
}
// Determine bind port
bindPort := os.Getenv("BIND_PORT")
if bindPort == "" {
bindIP = "8443"
}
bindAddress := fmt.Sprint(bindIP, ":", bindPort)
fmt.Printf("Will listen on address 'https://%s'\n", bindAddress)
// Generate certificate if required
tlsCertFilename := utils.GetFilePath(os.Getenv("TLS_CERT_FILE"))
tlsKeyFilename := utils.GetFilePath(os.Getenv("TLS_KEY_FILE"))
if !(utils.FileExists(tlsCertFilename) && utils.FileExists(tlsKeyFilename)) {
fmt.Printf("Specified TLS certificate (%s) or private key (%s) do not exist.\n", tlsCertFilename, tlsKeyFilename)
utils.GenerateCerts(tlsCertFilename, tlsKeyFilename)
}
srv := &http.Server{
Addr: ":8080",
Handler: router,
Addr: bindAddress,
Handler: router,
TLSConfig: tlsConfig,
}
// Register our routes
@@ -52,7 +95,7 @@ func main() {
// Initializing the server in a goroutine so that
// it won't block the graceful shutdown handling below
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
if err := srv.ListenAndServeTLS(tlsCertFilename, tlsKeyFilename); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()

View File

@@ -1,12 +1,22 @@
package utils
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"net"
"os"
"path/filepath"
"time"
)
const rsaBits = 4096
func GetFilePath(path string) string {
// Check for empty filename
if len(path) == 0 {
@@ -27,3 +37,150 @@ func GetFilePath(path string) string {
}
return path
}
// Get preferred outbound ip of this machine
// @see https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go
func GetOutboundIP() net.IP {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP
}
// Check if a file exists from https://stackoverflow.com/questions/12518876/how-to-check-if-a-file-exists-in-go
func FileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
func GenerateCerts(tlsCert string, tlsKey string) {
// @see https://shaneutt.com/blog/golang-ca-and-signed-cert-go/
// @see https://golang.org/src/crypto/tls/generate_cert.go
validFrom := ""
validFor := 365 * 24 * time.Hour
isCA := true
// Get the hostname
hostname, err := os.Hostname()
if err != nil {
panic(err)
}
// Check that the directory exists
relativePath := filepath.Dir(tlsCert)
fmt.Printf("GenerateCerts relative path for file creation is '%s'\n", relativePath)
_, err = os.Stat(relativePath)
if os.IsNotExist(err) {
log.Printf("Certificate path does not exist, creating %s before generating certificate\n", relativePath)
os.MkdirAll(relativePath, os.ModePerm)
}
// Generate a private key
priv, err := rsa.GenerateKey(rand.Reader, rsaBits)
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
var notBefore time.Time
if len(validFrom) == 0 {
notBefore = time.Now()
} else {
notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom)
if err != nil {
log.Fatalf("Failed to parse creation date: %v", err)
}
}
notAfter := notBefore.Add(validFor)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
log.Fatalf("Failed to generate serial number: %v", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"DTMS"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
template.DNSNames = append(template.DNSNames, hostname)
// Add in all the non-local IPs
ifaces, err := net.Interfaces()
if err != nil {
fmt.Printf("Error enumerating interfaces: %v\n", err)
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
fmt.Printf("Oops: %v\n", err)
}
for _, address := range addrs {
// check the address type and if it is not a loopback then add it to the list
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
template.IPAddresses = append(template.IPAddresses, ipnet.IP)
}
}
}
}
if isCA {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
log.Fatalf("Failed to create certificate: %v", err)
}
certOut, err := os.Create(tlsCert)
if err != nil {
log.Fatalf("Failed to open %s for writing: %v", tlsCert, err)
}
if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
log.Fatalf("Failed to write data to %s: %v", tlsCert, err)
}
if err := certOut.Close(); err != nil {
log.Fatalf("Error closing %s: %v", tlsCert, err)
}
log.Printf("wrote %s\n", tlsCert)
keyOut, err := os.OpenFile(tlsKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Failed to open %s for writing: %v", tlsKey, err)
return
}
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
log.Fatalf("Unable to marshal private key: %v", err)
}
if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
log.Fatalf("Failed to write data to %s: %v", tlsKey, err)
}
if err := keyOut.Close(); err != nil {
log.Fatalf("Error closing %s: %v", tlsKey, err)
}
log.Printf("wrote %s\n", tlsKey)
}