chore: run tests with tls using self-signed certificate

This commit is contained in:
Johan Siebens
2024-02-28 13:14:33 +01:00
parent 9a60430949
commit 62a7290e3d
8 changed files with 238 additions and 12 deletions
+1
View File
@@ -1,3 +1,4 @@
.git
.idea
tests
!tests/config/ca.pem
+140
View File
@@ -0,0 +1,140 @@
// partially taken from https://github.com/FiloSottile/mkcert
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"log"
"math/big"
"net"
"net/mail"
"net/url"
"os"
"path/filepath"
"time"
)
func main() {
path := "./tests/config"
caCert, caKey := newCA(path)
makeCert(path, caCert, caKey, []string{"ionscale"})
}
func generateKey(rootCA bool) (crypto.PrivateKey, error) {
if rootCA {
return rsa.GenerateKey(rand.Reader, 3072)
}
return rsa.GenerateKey(rand.Reader, 2048)
}
func makeCert(path string, caCert *x509.Certificate, caKey any, hosts []string) {
priv, err := generateKey(false)
fatalIfErr(err)
pub := priv.(crypto.Signer).Public()
expiration := time.Now().AddDate(2, 3, 0)
tpl := &x509.Certificate{
SerialNumber: randomSerialNumber(),
Subject: pkix.Name{
Organization: []string{"ionscale tests cert"},
OrganizationalUnit: []string{"ionscale"},
},
NotBefore: time.Now(), NotAfter: expiration,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
}
for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
tpl.IPAddresses = append(tpl.IPAddresses, ip)
} else if email, err := mail.ParseAddress(h); err == nil && email.Address == h {
tpl.EmailAddresses = append(tpl.EmailAddresses, h)
} else if uriName, err := url.Parse(h); err == nil && uriName.Scheme != "" && uriName.Host != "" {
tpl.URIs = append(tpl.URIs, uriName)
} else {
tpl.DNSNames = append(tpl.DNSNames, h)
}
}
if len(tpl.IPAddresses) > 0 || len(tpl.DNSNames) > 0 || len(tpl.URIs) > 0 {
tpl.ExtKeyUsage = append(tpl.ExtKeyUsage, x509.ExtKeyUsageServerAuth)
}
if len(tpl.EmailAddresses) > 0 {
tpl.ExtKeyUsage = append(tpl.ExtKeyUsage, x509.ExtKeyUsageEmailProtection)
}
cert, err := x509.CreateCertificate(rand.Reader, tpl, caCert, pub, caKey)
fatalIfErr(err)
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
privDER, err := x509.MarshalPKCS8PrivateKey(priv)
fatalIfErr(err)
privPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privDER})
fatalIfErr(os.WriteFile(filepath.Join(path, "ionscale.pem"), certPEM, 0644))
fatalIfErr(os.WriteFile(filepath.Join(path, "ionscale.key"), privPEM, 0600))
}
func newCA(path string) (*x509.Certificate, any) {
priv, err := generateKey(true)
fatalIfErr(err)
pub := priv.(crypto.Signer).Public()
spkiASN1, err := x509.MarshalPKIXPublicKey(pub)
fatalIfErr(err)
var spki struct {
Algorithm pkix.AlgorithmIdentifier
SubjectPublicKey asn1.BitString
}
_, err = asn1.Unmarshal(spkiASN1, &spki)
fatalIfErr(err)
skid := sha1.Sum(spki.SubjectPublicKey.Bytes)
tpl := &x509.Certificate{
SerialNumber: randomSerialNumber(),
Subject: pkix.Name{
Organization: []string{"ionscale tests CA"},
OrganizationalUnit: []string{"ionscale"},
CommonName: "ionscale",
},
SubjectKeyId: skid[:],
NotAfter: time.Now().AddDate(10, 0, 0),
NotBefore: time.Now(),
KeyUsage: x509.KeyUsageCertSign,
BasicConstraintsValid: true,
IsCA: true,
MaxPathLenZero: true,
}
cert, err := x509.CreateCertificate(rand.Reader, tpl, tpl, pub, priv)
fatalIfErr(err)
fatalIfErr(os.WriteFile(filepath.Join(path, "ca.pem"), pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644))
return tpl, priv
}
func randomSerialNumber() *big.Int {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
fatalIfErr(err)
return serialNumber
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}
+26
View File
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEVDCCArygAwIBAgIRAMIAYisvcyOuv3qmGjMmJqAwDQYJKoZIhvcNAQELBQAw
QjEaMBgGA1UEChMRaW9uc2NhbGUgdGVzdHMgQ0ExETAPBgNVBAsTCGlvbnNjYWxl
MREwDwYDVQQDEwhpb25zY2FsZTAeFw0yNDAyMjgxMDU1MjJaFw0zNDAyMjgxMDU1
MjJaMEIxGjAYBgNVBAoTEWlvbnNjYWxlIHRlc3RzIENBMREwDwYDVQQLEwhpb25z
Y2FsZTERMA8GA1UEAxMIaW9uc2NhbGUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw
ggGKAoIBgQDE2OSk75B3+2t/A/YxnCg0Ppz4Gzbw2oEZ2nw6bjDuIzjCOg+/CwoM
prFQcgEBmACKAnQ6gBvXhxVFQ4ROhqWlmGtQ7LzNG/ByKGI7h1hHz4jMJTDmCWH1
rfvIRvApUer+Pmp4+39/++WPhkdy4UWu1puVOWdaOIbPigzd5hpqihyWy5FdEKyA
d0V5ElnTNjUHOjJ2MM9f33VxGe3U21u785w4jXndLgG5IxMYfpeMZ0HtOu5JTrsB
ec8taLqM3SxClpOFOJWDgieb3eacpl5GARh+a5/lVEJtM1CJE4CEPwghjGtjow4E
7nze5pckPEetHtWEax9hz/dC7J/mcMa1MFgpKcxlaHotT0I9goCEdvEuHI0r0Nt5
TRfGjRTV2LGbHBnOY4Pn6N6OlfmesG4oTHErCkS9X1CZrB+Nxxywtvy1M2hEtbLY
bZMnWRhEoH8E9plWVS/HmyMza1rq4MEBv1BQhywoBChy+W+hqY1CQcdSgPeRj20F
JR9LvmD3W98CAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYB
Af8CAQAwHQYDVR0OBBYEFLNqb6/tfxMEdf8F13/mOausIT9hMA0GCSqGSIb3DQEB
CwUAA4IBgQCH0fc9cCYV5G7Oy0QVY5L0iYYz4aWXy1dsHxPtSvzbai0ZvNGupesp
fpsAb426mGp9vEJ+xQYnnTBhmvPJRZAbKbD2PV2vh/SpbD86gJS2azYneLSM0QXe
jgKb0aK/OSQYA5wzp/An1Yggg8SvT7SxS+fD4D7uD1UXPSqPjSO4IHT+8GPnm+rg
P3uierAyO5bAdE831yswTj33E4gm9HVKLqDW8YdIw9xI48T0ylj5F2DEQkSZWhFA
BqLN58e3zfo+3uh8KeVikd/k1KTQgrJeknDy12NMY1SzblBCEO8jF8LdraHn0RMy
QlJcRG315JNM0OIEbc22LeTUmeyJT7qrkERmoK1A7iRTQVpjJe4ZdocUtjKc03Pa
sAPs2xRXr58g9fVsN1ZevKSfvAvZWbXECdKRnw6z/LeqnjEpskbtcAoDoPV5cQ3L
1r9WpZYPq3D0Y9weX/XI0cGUnjIXqhY/mcBy/KwlVOfeen6eV0N6KYwDdd19zn8D
PRxxinJCKkg=
-----END CERTIFICATE-----
+5 -3
View File
@@ -1,9 +1,11 @@
web_listen_addr: ":80"
web_public_addr: "http://ionscale:80"
web_listen_addr: ":443"
web_public_addr: "ionscale:443"
tls:
disable: true
disable: false
force_https: false
key_file: /etc/ionscale/ionscale.key
cert_file: /etc/ionscale/ionscale.pem
keys:
system_admin_key: "804ecd57365342254ce6647da5c249e85c10a0e51e74856bfdf292a2136b4249"
+28
View File
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDOcaJGhEiAO/Tu
usxtQWbuxIqotV7bDdyQRBlLhPb2UORo6U+KNNP26xPWv8eSg4P1hYroyRGPGRtQ
e6if49cYTRxh26lzO/umLfjFbiY4nyVpXVtOEwpz9A6okRgno7k/TVw4cCriXnIg
bqqwhK+FBGWVT/yTxVYE8OXJ5oIzD8XJ9ZVekSCNr/Pn5HmklViyMuGdH49yEIRt
LOPLW3dU5Rt8vPyWec1w/KJQyScBUMS/yk1r1Tc/FT90RpHqiJRcVIZQG1RZEOg0
+rgoaEW8XsoLIPUHqBqkAuM2pPvAtTzPwKjA6ktel+FdRRwNCe5NEy95BBBBDyF0
QsqhGRV5AgMBAAECggEAPjXGBeP1CReIPqxxz/amcwstEZveIrqxnZO336cI2L8V
pXuxKV+0BDNgvhT6qe8Rw9njOzTkIrAZKA6riMsa1UrfY6nTDVOlCLXPwobn46Yp
mu+0BPn962U/SZK3qbJPr4C7apJ6ic6WK6nNq/XAAqCJkA4TeeA8hK6nQElDMOlk
JrSbpRpqUs9H+LYGUPku+Ti33UMcz/DWtHM2XpaXM7MWkkNQfu2Z89lQbeGoLLVP
FA90ufwh9o6z2kTkscDuCT+iYQvf5W4Yu3MYugdHt9am7JbDWx1FGJf0vosg7Ckb
A5ccEK5791bjn+41oTUKcjJnRfDenFUyxs2JMaV/RQKBgQDbRk2shTk00DRAeQhl
sEzv7kyjKVEdo52Xd4Z0MKwcTwBGuEF91fvC1saSxFii5MVu8uFnCzZby63yxbqp
PKyncGSI8uHSDNN2nKlcrWa8ecFPWloU2qNFka7Pj8tcAt7fXN/x0BOeyPl2ZgKI
JjGJ5zEY1ZRjUVajaFPCLb9wPwKBgQDxBTHx0qq4j4J7tOJWrFVfY1GFoXYXBzDs
mxgLEXm7Tln7/O+1bOUOsViaSR+JlwkMzYMYAX0+5Dwq2X7D5UeICzHboF44VCxb
WA0RUcI3fXX/fXYvB4kgcDq697MyUd7uXMz9aJtL8y9x3UWkg7YBtcLa8Nj22NS/
5aNOGMIMRwKBgF4SJzigXw59VC1kv2mA3UEB5vcIvrgMfYuBx7kJOI1chy3P1qj5
qGzKX56Phcc8hkc3A+SFNuji1NmWYqJAWYHsAfWO3bqTrhTw2OfdrHmncntss8DG
m8041tpNQl1TDfKdkaXYMtKoPf3BfcyTNiWHfdS9rE9/kb/A/k4L+llZAoGAUDV8
Y4/KRNVthSGzWUjMuIvi62fKVuuLupH6tGRCcLUoeRW56FSu/e7DH8VJ+44J8vrJ
r8l/Ftj5tQDgkOzSm1Gua/q4oGJSyKtK3gKpcbIM/NOR6yDE38i5otMgDZT1bbnw
djzDwcjSd0A+FvvGLFeC2z3f1nZehuYzLKBMo60CgYAPjANh0rVnCbbnsQYwLJa7
83vatZWtb4Qy1VJcsGT6TFqf3gUTKel8KttM2RN0rs9nZ/Slso9q778Fv16aTnlI
48P8x8Qw+Zen7042NvrsjnXcOi4sj0b2SLWvOBDBO7eY7GXSqa7O0PpPUSD7vTLu
EDO0H/OF6MRC8YSaz8WrkQ==
-----END PRIVATE KEY-----
+23
View File
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID2jCCAkKgAwIBAgIQSH/qIg/vOs/ZPoTlMlg2GDANBgkqhkiG9w0BAQsFADBC
MRowGAYDVQQKExFpb25zY2FsZSB0ZXN0cyBDQTERMA8GA1UECxMIaW9uc2NhbGUx
ETAPBgNVBAMTCGlvbnNjYWxlMB4XDTI0MDIyODEwNTUyMloXDTI2MDUyODA5NTUy
MlowMTEcMBoGA1UEChMTaW9uc2NhbGUgdGVzdHMgY2VydDERMA8GA1UECxMIaW9u
c2NhbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOcaJGhEiAO/Tu
usxtQWbuxIqotV7bDdyQRBlLhPb2UORo6U+KNNP26xPWv8eSg4P1hYroyRGPGRtQ
e6if49cYTRxh26lzO/umLfjFbiY4nyVpXVtOEwpz9A6okRgno7k/TVw4cCriXnIg
bqqwhK+FBGWVT/yTxVYE8OXJ5oIzD8XJ9ZVekSCNr/Pn5HmklViyMuGdH49yEIRt
LOPLW3dU5Rt8vPyWec1w/KJQyScBUMS/yk1r1Tc/FT90RpHqiJRcVIZQG1RZEOg0
+rgoaEW8XsoLIPUHqBqkAuM2pPvAtTzPwKjA6ktel+FdRRwNCe5NEy95BBBBDyF0
QsqhGRV5AgMBAAGjXTBbMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEF
BQcDATAfBgNVHSMEGDAWgBSzam+v7X8TBHX/Bdd/5jmrrCE/YTATBgNVHREEDDAK
gghpb25zY2FsZTANBgkqhkiG9w0BAQsFAAOCAYEALUO2i7zsClFSTdBzMEsPupAd
TYMxFG0ms8jBma9VixQycudiLS5ICgoGErXtYqsfHOOi3OxwZ8SUVF3JnqaWStFD
Hi3ckdjBprBJEVXaZUGSeaKJHYIuBrFZBf5uhtd7o9qC3uPYLp8yzdDM/JsyRCl9
V7NUq69fKkYi1vokHwL0xTU+hbTygVAsok1j4E2dBmtLpRsfokjAExdx5QykIlh2
mAf2owD1e2JY9bW1zHZpgkfapV6bv95jrKSerG0PM/fUpZ3/QxjB0OenQXHz2dcK
hIS+lWj+Sns6m5iyTsLVQyw4giLTGLDPAztWotA+zaHUcS6iR9nrChZ5J4tklRD4
+OAmL+iiR4z0aIED/CLRiw27W/m8+K5XfisTfNk6IhgsE/cILAhxnHJy6asa/0pT
KanbA1ilcr3nAYuETW39f2NIrjvm8ELvrOrzC5LB75FxoJyp799QO939XqSKwoxL
T4JDjOOprtH1cPwag5MJF6NZj0fb2ej77RR3R5cI
-----END CERTIFICATE-----
+2
View File
@@ -4,6 +4,8 @@ FROM tailscale/tailscale:${TAILSCALE_VERSION} as src
FROM alpine:latest
RUN apk update && apk add ca-certificates openssh curl && rm -rf /var/cache/apk/*
COPY ./tests/config/ca.pem /usr/local/share/ca-certificates/
RUN update-ca-certificates
WORKDIR /app
COPY --from=src /usr/local/bin/tailscale .
+12 -8
View File
@@ -169,7 +169,7 @@ func (s *Scenario) NewTailscaleNode(opts ...TailscaleNodeOpt) *tsn.TailscaleNode
s.resources = append(s.resources, resource)
return tsn.New(s.t, config.Hostname, "http://ionscale", resource, s.pool.Retry)
return tsn.New(s.t, config.Hostname, "https://ionscale", resource, s.pool.Retry)
}
func Run(t *testing.T, f func(s *Scenario)) {
@@ -247,25 +247,28 @@ func Run(t *testing.T, f func(s *Scenario)) {
fmt.Sprintf("%s/config:/etc/ionscale", currentPath),
},
Networks: []*dockertest.Network{s.network},
ExposedPorts: []string{"80"},
ExposedPorts: []string{"443"},
Cmd: []string{"server", "--config", "/etc/ionscale/config.yaml"},
}
s.ionscale, err = pool.RunWithOptions(ionscale, restartPolicy)
require.NoError(s.t, err)
port := s.ionscale.GetPort("80/tcp")
port := s.ionscale.GetPort("443/tcp")
err = pool.Retry(httpCheck(port, "/key"))
require.NoError(s.t, err)
addr := fmt.Sprintf("http://localhost:%s", port)
addr := fmt.Sprintf("https://localhost:%s", port)
auth, err := ionscaleclt.LoadClientAuth(addr, "804ecd57365342254ce6647da5c249e85c10a0e51e74856bfdf292a2136b4249")
require.NoError(s.t, err)
s.ionscaleClient, err = ionscaleclt.NewClient(auth, addr, true)
require.NoError(s.t, err)
err = pool.Retry(func() error {
_, err := s.ionscaleClient.GetVersion(context.Background(), connect.NewRequest(&api.GetVersionRequest{}))
return err
})
require.NoError(s.t, err)
f(s)
}
@@ -313,7 +316,8 @@ func prepareDockerPoolAndImages() {
pool, _ = dockertest.NewPool("")
buildOpts := &dockertest.BuildOptions{
ContextDir: "./docker/tailscale",
ContextDir: "../",
Dockerfile: "tests/docker/tailscale/Dockerfile",
BuildArgs: []docker.BuildArg{
{
Name: "TAILSCALE_VERSION",