# Correctly passes TLS client config to the upstream

exec bash -x ./tls.sh
exec bash -x ./test.sh &
exec bash -c 'I=0 ; while [ ! -f alertmanager.pid ] && [ $I -lt 30 ]; do sleep 1; I=$((I+1)); done'
exec karma --pid-file=karma.pid
! stdout .
stderr 'level=INFO msg="Upstream version" version=0.24.0 alertmanager=client-auth'
stderr 'level=INFO msg="Got silences" alertmanager=client-auth silences=0 duration=.+'
stderr 'level=INFO msg="Detecting ticket links in silences" alertmanager=client-auth silences=0'
stderr 'level=INFO msg="Collected alert groups" alertmanager=client-auth groups=0 duration=.+'
stderr 'level=INFO msg="Deduplicating alert groups" alertmanager=client-auth groups=0'
stderr 'level=INFO msg="Processing deduplicated alert groups" alertmanager=client-auth groups=0'
stderr 'level=INFO msg="Merging autocomplete hints" alertmanager=client-auth hints=0'
stderr 'level=INFO msg="Collection completed"'
wait

-- alertmanager.conf --
[req]
distinguished_name = DN
x509_extensions = SAN
[DN]
CN = 127.0.0.1
[SAN]
basicConstraints     = CA:FALSE
subjectKeyIdentifier = hash
keyUsage             = digitalSignature, keyEncipherment
extendedKeyUsage     = clientAuth, serverAuth
subjectAltName       = @alt_names
[alt_names]
DNS.1 = localhost
IP.1  = 127.0.0.1

-- karma.conf --
[req]
distinguished_name = DN
req_extensions = SAN
[DN]
CN = karma
[SAN]
basicConstraints     = CA:FALSE
subjectKeyIdentifier = hash
keyUsage             = digitalSignature, keyEncipherment
extendedKeyUsage     = clientAuth, serverAuth
subjectAltName       = @alt_names
[alt_names]
DNS.1 = karma

-- tls.sh --
openssl ecparam -genkey -name secp256r1 | openssl ec -out ca.key
openssl req -new -x509 -sha256 -days 7 -key ca.key -out ca.pem -subj "/C=CI/ST=CI/L=CI/O=CI/CN=FakeCA"

openssl ecparam -genkey -name secp256r1 | openssl ec -out alertmanager.key
openssl req -new -key alertmanager.key -out alertmanager.csr -subj "/C=CI/ST=CI/L=CI/O=CI/CN=127.0.0.1" -config alertmanager.conf -extensions SAN
openssl x509 -req -sha256 -days 7 -extfile alertmanager.conf -extensions SAN -in alertmanager.csr -CA ca.pem -CAkey ca.key -set_serial 01 -out alertmanager.pem
openssl x509 -in alertmanager.pem -text

openssl ecparam -genkey -name secp256r1 | openssl ec -out karma.key
openssl req -new -key karma.key -out karma.csr -subj "/C=CI/ST=CI/L=CI/O=CI/CN=karma" -config karma.conf -extensions SAN
openssl x509 -req -sha256 -days 7 -extfile karma.conf -extensions SAN -in karma.csr -CA ca.pem -CAkey ca.key -set_serial 02 -out karma.pem
openssl x509 -in karma.pem -text

-- test.sh --
env GOCACHE=$TMPDIR go run alertmanager.go &

I=0
while [ ! -f karma.pid ] && [ $I -lt 30 ]; do sleep 1; I=$((I+1)); done

sleep 5
cat karma.pid | xargs kill
cat alertmanager.pid | xargs kill

-- karma.yaml --
alertmanager:
  interval: 1h
  servers:
    - name: client-auth
      uri: https://127.0.0.1:9096
      timeout: 10s
      tls:
        ca: ca.pem
        cert: karma.pem
        key: karma.key
listen:
  address: 127.0.0.1
  port: 8096

-- alertmanager.go --
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

func metrics(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
	io.WriteString(w, `alertmanager_build_info{version="0.24.0"} 1
`)
}

func empty(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, "[]")
}

func main() {
	pid := os.Getpid()
	err := os.WriteFile("alertmanager.pid", []byte(strconv.Itoa(pid)), 0644)
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/metrics", metrics)
	http.HandleFunc("/api/v2/silences", empty)
	http.HandleFunc("/api/v2/alerts/groups", empty)

	caCert, err := os.ReadFile("ca.pem")
	if err != nil {
		log.Fatal(err)
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)

	tlsConfig := &tls.Config{
		ClientCAs:          caCertPool,
		ClientAuth:         tls.RequireAndVerifyClientCert,
		InsecureSkipVerify: true,
	}

	listener, err := net.Listen("tcp", "127.0.0.1:9096")
	if err != nil {
		log.Fatal(err)
	}

	server := &http.Server{
		Addr:      "127.0.0.1:9096",
		TLSConfig: tlsConfig,
	}

	go func() {
		err := server.ServeTLS(listener, "alertmanager.pem", "alertmanager.key")
		if err != nil {
			log.Printf("ServeTLS returned error: %v", err)
		}
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
	<-stop
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	server.Shutdown(ctx)
}
