GithubHelp home page GithubHelp logo

dyson / certman Goto Github PK

View Code? Open in Web Editor NEW
31.0 6.0 5.0 22 KB

Go TLS certificate reloading for the standard library http server.

Home Page: https://github.com/dyson/certman

License: MIT License

Go 100.00%
go https tls certificate livereload

certman's Introduction

Certman

version Build Status Coverage Status Code Climate Go Report Card

GoDoc license

Go TLS certificate reloading for the standard library http server.

Certman watches for changes to your certificate and key files and reloads them on change allowing the server to stay online during certificate changes. Useful for Let's Encrypt but also just in general as there's no reason to bring your servers down just to update certificates and keys.

Limitation

Certman handles only a single certificate and key pair and responds to all requests with this pair. It ignores if the client is sending a server name using SNI. I'm not sure if there's a generic enough way to implement this that handles all use cases and as it's a niche feature I haven't needed so I've left it out (pull requests welcome!). Certman's codebase is small so either fork the repo or copy and paste it into your project and modify it to your needs.

Installation

Using dep for dependency management (https://github.com/golang/dep):

dep ensure github.com/dyson/certman

Using go get:

$ go get github.com/dyson/certman

Usage

Generate a cert and key:

$ openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -sha256 -keyout /tmp/server.key -out /tmp/server.crt

Basic server passing in a logger to log certman events:

package main

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/dyson/certman"
)

func main() {
	logger := log.New(os.Stdout, "", log.LstdFlags)

	cm, err := certman.New("/tmp/server.crt", "/tmp/server.key")
	if err != nil {
		logger.Println(err)
	}
	cm.Logger(logger)
	if err := cm.Watch(); err != nil {
		logger.Println(err)
	}

	http.HandleFunc("/", handler)
	s := &http.Server{
		Addr: ":8080",
		TLSConfig: &tls.Config{
			GetCertificate: cm.GetCertificate,
		},
	}
	if err := s.ListenAndServeTLS("", ""); err != nil {
		logger.Println(err)
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello")
}

Visit https://localhost:8080.

Overwrite exising certificate and key using the openssl gen command above.

Visit https://localhost:8080 again. Notice how existing requests are continued to be served by the old certificate.

Visit https://localhost:8080 in another browser and see the new certificate is being served for new requests.

Running example:

$ go run main.go
2017/08/01 16:05:23 certman: certificate and key loaded
2017/08/01 16:05:23 certman: watching for cert and key change
# Regenerated certificate and key here
2017/08/01 16:06:30 certman: watch event: "/tmp/server.key": WRITE
2017/08/01 16:06:30 certman: can't load cert or key file: tls: private key does not match public key
2017/08/01 16:06:30 certman: watch event: "/tmp/server.key": WRITE
2017/08/01 16:06:30 certman: can't load cert or key file: tls: private key does not match public key
2017/08/01 16:06:32 certman: watch event: "/tmp/server.crt": WRITE
2017/08/01 16:06:32 certman: certificate and key loaded
# Certificate loaded once the certificate and key can both be read correctly and they match

License

See LICENSE file.

certman's People

Contributors

dyson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

certman's Issues

certs stops reloading

I ran into an issue where the certs would stop reloading when we rotated them in our kubernetes environment. We imported this small library to handle the tls secret rotations that happen when but after the second rotation we got some TLS errors in our replica sets that came up. After the first rotation you will notice the certman logs stops running.

we saw the logs would stop appearing after a rotation.

2022/02/03 03:57:53 certman: watch event: "/run/secrets/tls/tls.key": REMOVE
2022/02/03 03:57:53 certman: certificate and key loaded
2022/02/03 03:57:53 certman: watch event: "/run/secrets/tls/tls.crt": CHMOD
2022/02/03 03:57:53 certman: certificate and key loaded
2022/02/03 03:57:53 certman: watch event: "/run/secrets/tls/tls.crt": REMOVE
2022/02/03 03:57:53 certman: certificate and key loaded

The error was the following:

Error creating: Internal error occurred: failed calling webhook "janus.mutating.custom-admission-webhooks<redacted>": Post "https://janus.ns-team-janus.svc:443/janus/v1/sidecar?timeout=2s": x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "<redacted>")

We noticed the cert that was mounted as a volume mount in our deployment object didn't match the one that was being served for our service runtime.

we consume our secret via kubernetes volume secret

      volumes:
        - name: janus-webhook-tls
          secret:
            secretName: janus-webhook-tls

We verified by grabbing the cert with the following command and noticed the dates were older than the originally rotated cert on the volume mount.

/ # echo | openssl s_client -servername <service-endpoint> -connect <service-endpoint>:<port>

Cert that was mounted via volume was the new one.

        Validity
            Not Before: Feb  8 12:27:12 2022 GMT
            Not After : Aug  8 12:27:12 2022 GMT

vs.
cert that was exposed via the openssl command is old.

        Validity
            Not Before: Feb  2 03:56:21 2022 GMT
            Not After : Aug  2 03:56:20 2022 GMT

There is already a PR filed that seems to address the same issue.
#1
The issue seemed to be the timing of the load the event that was being triggered and we also changed the the fsnotify to monitor the directory instead other individual files. This PR had to be tweak for us to get it to work in our application.
https://github.com/ts3ng/certman/tree/fix-reload

LMK if you want me to open PR as this lib doesn't look like it's been maintained for a while now.

RWLock is important?

The GetCertificate uses a RWLock

func (cm *CertMan) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
	cm.mu.RLock()
	defer cm.mu.RUnlock()

	return cm.keyPair, nil
}

Is the lock is really needed? There is really no concurrent modifications. But the lock makes performance slower.

Check for certs changed at midnight

the certbot renews certs many days before expiration so it's really no rush to update certs. Maybe just check for reload a cert once a day instead of the fs notify watch?
The fs notify is platform specific and implemented as a dependency but also the inotify is slow as far I know.
Or I missing something important?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.