Commit aa97124c authored by Geoff Simmons's avatar Geoff Simmons

Initial commit, initial implementation of package pkg/crt.

parents
See LICENSE for details.
Copyright (c) 2020 UPLEX Nils Goroll Systemoptimierung
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
# Copyright (c) 2020 UPLEX Nils Goroll Systemoptimierung
# All rights reserved
#
# Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
all: build
CODE_SUBDIRS=./pkg/...
build:
go fmt $(CODE_SUBDIRS)
go generate $(CODE_SUBDIRS)
go build $(CODE_SUBDIRS)
check: build
golint ./pkg/crt/...
go test -v ./pkg/crt/...
test: check
clean:
go clean $(CODE_SUBDIRS)
# Kubernetes Certiicate Downloader
An application that watches TLS Secrets in a Kubernetes cluster, and
provides a REST API with which a client can instruct the app to save
Secrets as certificate/key files in a local directory, or to update or
delete existing files.
This application is primarily meant to support the use of
[haproxy](http://www.haproxy.org/), in particular since it saves the
TLS certificates and keys concatenated in single files, as haproxy
requires.
module code.uplex.de/k8s/k8s-crt-dnldr
require (
github.com/sirupsen/logrus v1.6.0
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f
k8s.io/api v0.16.4
k8s.io/apimachinery v0.16.4
k8s.io/client-go v0.16.4
)
This diff is collapsed.
/*
* Copyright (c) 2020 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// Package crt encapsulates the validation and retrieval of a TLS
// Secret's data from a Kubernetes client-go lister. Only the
// crt.Getter type should be used to access the contents of Secrets.
package crt
import (
"errors"
api_v1 "k8s.io/api/core/v1"
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
core_v1_listers "k8s.io/client-go/listers/core/v1"
)
const (
crtKey = "tls.crt"
keyKey = "tls.key"
)
// A Getter retrieves and validates data from TLS Secrets.
type Getter struct {
lister core_v1_listers.SecretLister
}
// NewGetter returns a new instance of Getter, which retrieves data
// from the client-go SecretLister that is provided. This should be
// the same lister that is populated by a client-go client that is
// watching the cluster API.
func NewGetter(lister core_v1_listers.SecretLister) *Getter {
return &Getter{lister: lister}
}
// Get retrieves a Secret's data based on its Namespace and Name, and
// optionally on its UID and ResourceVersion. If found, the Secret is
// checked for validity as a TLS Secret.
//
// ns and name MUST be set to the Namespace and Name of the desired
// Secret. Either or both of uid and version MAY be empty. If uid
// and/or version is non-empty, then the Secret is found iff the
// corresponding UID and/or ResourceVersion of the Secret match. This
// way, a client can request a specific version of the Secret, or just
// the version of the Secret currently stored by the SecretLister.
//
// The return value found is true iff the Secret is found.
//
// If the Secret is found, then it is validated as a TLS Secret. Both
// of the keys "tls.crt" and "tls.key" MUST be present in the Secret
// data, and their values MUST be non-empty. If one of the two keys is
// missing, then the return value valid is false, and err is non-nil,
// returning the message "required field missing". If one of the
// values is empty, then valid is false and non-nil err returns the
// message "required field empty".
//
// Moreover, the Secret's type field MUST be set to
// "kubernetes.io/tls". Otherwise valid is false, and non-nil err
// returns the message "invalid type value". (This should never happen
// if the watcher that populates the SecretLister filters Secrets for
// this value of type).
//
// No more than one of the return values found or valid will be false.
// Retrieval and validation of the Secret was successful if found and
// valid are both true, and err is nil.
//
// If the operation was successful, then the return values crt and key
// contain the values from "tls.crt" and "tls.key" in the Secret data.
// The return values suid and sversion contain the values of the
// Secret's UID and ResourceVersion fields.
func (getter *Getter) Get(
ns, name, uid, version string,
) (crt, key []byte, suid, sversion string, found, valid bool, err error) {
valid = true
nsLister := getter.lister.Secrets(ns)
secret, err := nsLister.Get(name)
if err != nil {
if k8s_errors.IsNotFound(err) {
return
}
found = true
return
}
suid = string(secret.UID)
sversion = secret.ResourceVersion
if uid != "" && suid != uid {
return
}
if version != "" && sversion != version {
return
}
found = true
if secret.Type != api_v1.SecretTypeTLS {
err = errors.New("invalid type value")
valid = false
return
}
crt, valid = secret.Data[crtKey]
if !valid {
err = errors.New("required field missing")
return
}
if len(crt) == 0 {
valid = false
err = errors.New("required field empty")
return
}
key, valid = secret.Data[keyKey]
if !valid {
err = errors.New("required field missing")
return
}
if len(key) == 0 {
valid = false
err = errors.New("required field empty")
}
return
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment