Fix dependency and linter errors.

This commit is contained in:
Mariano Cano 2019-02-11 20:27:41 -08:00
parent 0eb0c3a21b
commit 852f4ed564
10 changed files with 338 additions and 143 deletions

154
Gopkg.lock generated
View file

@ -35,6 +35,14 @@
revision = "b90dc15cfd220ecf8bbc9043ecb928cef381f011"
version = "v0.3.4"
[[projects]]
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
name = "github.com/ghodss/yaml"
packages = ["."]
pruneopts = "UT"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:81fda4d18a16651bf92245ce5d6178cdd99f918db30ae9794732655f0686e895"
@ -43,6 +51,17 @@
pruneopts = "UT"
revision = "0ebf7795c516423a110473652e9ba3a59a504863"
[[projects]]
digest = "1:b402bb9a24d108a9405a6f34675091b036c8b056aac843bf6ef2389a65c5cf48"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys",
]
pruneopts = "UT"
revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7"
version = "v1.2.0"
[[projects]]
branch = "travis-1.9"
digest = "1:e8f5d9c09a7209c740e769713376abda388c41b777ba8e9ed52767e21acf379f"
@ -54,6 +73,28 @@
pruneopts = "UT"
revision = "883fe33ffc4344bad1ecd881f61afd5ec5d80e0a"
[[projects]]
digest = "1:0f1010da61da43ef23bae5c43a619abda82e04f409ec642e6bdeee0d7736530d"
name = "github.com/google/certificate-transparency-go"
packages = [
".",
"asn1",
"tls",
"x509",
"x509/pkix",
]
pruneopts = "UT"
revision = "3629d6846518309d22c16fee15d1007262a459d2"
version = "v1.0.21"
[[projects]]
branch = "master"
digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb"
name = "github.com/google/gofuzz"
packages = ["."]
pruneopts = "UT"
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
branch = "master"
digest = "1:750e747d0aad97b79f4a4e00034bae415c2ea793fd9e61438d966ee9c79579bf"
@ -70,6 +111,14 @@
pruneopts = "UT"
revision = "1003c8bd00dc2869cb5ca5282e6ce33834fed514"
[[projects]]
digest = "1:3e551bbb3a7c0ab2a2bf4660e7fcad16db089fdcfbb44b0199e62838038623ea"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = "UT"
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
version = "v1.1.5"
[[projects]]
branch = "master"
digest = "1:e51f40f0c19b39c1825eadd07d5c0a98a2ad5942b166d9fc4f54750ce9a04810"
@ -125,6 +174,22 @@
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
version = "v0.0.4"
[[projects]]
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
name = "github.com/modern-go/concurrent"
packages = ["."]
pruneopts = "UT"
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3"
[[projects]]
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
name = "github.com/modern-go/reflect2"
packages = ["."]
pruneopts = "UT"
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1"
[[projects]]
digest = "1:266d082179f3a29a4bdcf1dcc49d4a304f5c7107e65bd22d1fecacf45f1ac348"
name = "github.com/newrelic/go-agent"
@ -212,7 +277,7 @@
[[projects]]
branch = "master"
digest = "1:4c9e30abfe7c119eb4d40287f6c23f854f3ad71c69206d8dc6402e1fef14ac88"
digest = "1:17d4424defbc718315d61e296841867ff76b3e03a941b41fdddbae11a7d47746"
name = "github.com/smallstep/cli"
packages = [
"command",
@ -226,6 +291,8 @@
"jose",
"pkg/blackfriday",
"pkg/x509",
"token",
"token/provision",
"ui",
"usage",
"utils",
@ -333,6 +400,14 @@
pruneopts = "UT"
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
[[projects]]
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
name = "gopkg.in/inf.v0"
packages = ["."]
pruneopts = "UT"
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
[[projects]]
digest = "1:7fbe10f3790dc4e6296c7c844c5a9b35513e5521c29c47e10ba99cd2956a2719"
name = "gopkg.in/square/go-jose.v2"
@ -354,20 +429,90 @@
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
branch = "master"
digest = "1:767b6c0b2c1d9487ee50cb8df1d0fdebf06ac0b19b723f6489d388e7b47c962d"
name = "k8s.io/api"
packages = [
"admission/v1beta1",
"authentication/v1",
"core/v1",
]
pruneopts = "UT"
revision = "de494049e22a9ccf748c5bbda7492f42f344d0cd"
[[projects]]
branch = "master"
digest = "1:5eb353533eaebdfec2392210ab218a389965ba5d4dc02b4aef87b9549e5d0f84"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/resource",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/conversion",
"pkg/conversion/queryparams",
"pkg/fields",
"pkg/labels",
"pkg/runtime",
"pkg/runtime/schema",
"pkg/runtime/serializer",
"pkg/runtime/serializer/json",
"pkg/runtime/serializer/protobuf",
"pkg/runtime/serializer/recognizer",
"pkg/runtime/serializer/versioning",
"pkg/selection",
"pkg/types",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/naming",
"pkg/util/net",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/yaml",
"pkg/watch",
"third_party/forked/golang/reflect",
]
pruneopts = "UT"
revision = "4b3b852955ebe47857fcf134b531b23dd8f3e793"
[[projects]]
digest = "1:72fd56341405f53c745377e0ebc4abeff87f1a048e0eea6568a20212650f5a82"
name = "k8s.io/klog"
packages = ["."]
pruneopts = "UT"
revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0"
version = "v0.2.0"
[[projects]]
digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849"
name = "sigs.k8s.io/yaml"
packages = ["."]
pruneopts = "UT"
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
version = "v1.1.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/alecthomas/gometalinter",
"github.com/client9/misspell/cmd/misspell",
"github.com/ghodss/yaml",
"github.com/go-chi/chi",
"github.com/golang/lint/golint",
"github.com/google/certificate-transparency-go",
"github.com/google/certificate-transparency-go/x509",
"github.com/gordonklaus/ineffassign",
"github.com/newrelic/go-agent",
"github.com/pkg/errors",
"github.com/rs/xid",
"github.com/sirupsen/logrus",
"github.com/smallstep/assert",
"github.com/smallstep/cli/config",
"github.com/smallstep/cli/crypto/keys",
"github.com/smallstep/cli/crypto/pemutil",
"github.com/smallstep/cli/crypto/randutil",
@ -376,12 +521,19 @@
"github.com/smallstep/cli/errs",
"github.com/smallstep/cli/jose",
"github.com/smallstep/cli/pkg/x509",
"github.com/smallstep/cli/token",
"github.com/smallstep/cli/token/provision",
"github.com/smallstep/cli/usage",
"github.com/tsenart/deadcode",
"github.com/urfave/cli",
"golang.org/x/net/http2",
"gopkg.in/square/go-jose.v2",
"gopkg.in/square/go-jose.v2/jwt",
"k8s.io/api/admission/v1beta1",
"k8s.io/api/core/v1",
"k8s.io/apimachinery/pkg/apis/meta/v1",
"k8s.io/apimachinery/pkg/runtime",
"k8s.io/apimachinery/pkg/runtime/serializer",
]
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -113,12 +113,3 @@ func NewInClusterK8sClient() (Client, error) {
httpClient: httpClient,
}, nil
}
// NewInsecureK8sClient creates an insecure k8s client which is suitable
// to connect kubernetes api behind proxy
func NewInsecureK8sClient(apiURL string) Client {
return &k8sClient{
host: apiURL,
httpClient: http.DefaultClient,
}
}

View file

@ -3,8 +3,8 @@ package main
import (
"context"
"crypto/sha256"
"encoding/json"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
@ -18,8 +18,8 @@ import (
"github.com/smallstep/certificates/ca"
"github.com/smallstep/cli/crypto/pemutil"
"k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)
@ -30,8 +30,8 @@ var (
deserializer = codecs.UniversalDeserializer()
// GetRootCAPath() is broken; points to secrets not certs. So
// we'll hard code instead for now.
//rootCAPath = pki.GetRootCAPath()
rootCAPath = "/home/step/.step/certs/root_ca.crt"
//rootCAPath = pki.GetRootCAPath()
rootCAPath = "/home/step/.step/certs/root_ca.crt"
)
const (
@ -45,23 +45,23 @@ const (
// Config options for the autocert admission controller.
type Config struct {
LogFormat string `yaml:"logFormat"`
CaUrl string `yaml:"caUrl"`
CertLifetime string `yaml:"certLifetime"`
Bootstrapper corev1.Container `yaml:"bootstrapper"`
Renewer corev1.Container `yaml:"renewer"`
CertsVolume corev1.Volume `yaml:"certsVolume"`
LogFormat string `yaml:"logFormat"`
CaURL string `yaml:"caUrl"`
CertLifetime string `yaml:"certLifetime"`
Bootstrapper corev1.Container `yaml:"bootstrapper"`
Renewer corev1.Container `yaml:"renewer"`
CertsVolume corev1.Volume `yaml:"certsVolume"`
}
// RFC6902 JSONPatch Operation
// PatchOperation represents a RFC6902 JSONPatch Operation
type PatchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
// RFC6901 JSONPath Escaping -- https://tools.ietf.org/html/rfc6901
func escapeJsonPath(path string) string {
func escapeJSONPath(path string) string {
// Replace`~` with `~0` then `/` with `~1`. Note that the order
// matters otherwise we'll turn a `/` into a `~/`.
path = strings.Replace(path, "~", "~0", -1)
@ -79,7 +79,7 @@ func loadConfig(file string) (*Config, error) {
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}
@ -88,19 +88,19 @@ func loadConfig(file string) (*Config, error) {
// A goroutine is scheduled to cleanup the secret after the token expires. The secret
// is also labelled for easy identification and manual cleanup.
func createTokenSecret(prefix, namespace, token string) (string, error) {
secret := corev1.Secret {
TypeMeta: metav1.TypeMeta {
secret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta {
ObjectMeta: metav1.ObjectMeta{
GenerateName: prefix,
Namespace: namespace,
Labels: map[string]string {
Labels: map[string]string{
tokenSecretLabel: "true",
},
},
StringData: map[string]string {
StringData: map[string]string{
tokenSecretKey: token,
},
Type: corev1.SecretTypeOpaque,
@ -162,7 +162,7 @@ func createTokenSecret(prefix, namespace, token string) (string, error) {
time.Sleep(tokenLifetime)
req, err := client.DeleteRequest(fmt.Sprintf("api/v1/namespaces/%s/secrets/%s", namespace, created.Name))
ctxLog := log.WithFields(log.Fields{
"name": created.Name,
"name": created.Name,
"namespace": namespace,
})
if err != nil {
@ -176,7 +176,7 @@ func createTokenSecret(prefix, namespace, token string) (string, error) {
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
ctxLog.WithFields(log.Fields{
"status": resp.Status,
"status": resp.Status,
"statusCode": resp.StatusCode,
}).Error("Error deleting expired boostrap token secret")
return
@ -206,109 +206,109 @@ func mkBootstrapper(config *Config, commonName string, namespace string, provisi
sum := sha256.Sum256(crt.Raw)
fingerprint := strings.ToLower(hex.EncodeToString(sum[:]))
secretName, err := createTokenSecret(commonName + "-", namespace, token)
secretName, err := createTokenSecret(commonName+"-", namespace, token)
if err != nil {
return b, errors.Wrap(err, "create token secret")
}
log.Infof("Secret name is: %s", secretName)
b.Env = append(b.Env, corev1.EnvVar {
Name: "COMMON_NAME",
b.Env = append(b.Env, corev1.EnvVar{
Name: "COMMON_NAME",
Value: commonName,
})
b.Env = append(b.Env, corev1.EnvVar {
b.Env = append(b.Env, corev1.EnvVar{
Name: "STEP_TOKEN",
ValueFrom: &corev1.EnvVarSource {
SecretKeyRef: &corev1.SecretKeySelector {
LocalObjectReference: corev1.LocalObjectReference {
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
Key: tokenSecretKey,
},
},
})
b.Env = append(b.Env, corev1.EnvVar {
Name: "STEP_CA_URL",
Value: config.CaUrl,
b.Env = append(b.Env, corev1.EnvVar{
Name: "STEP_CA_URL",
Value: config.CaURL,
})
b.Env = append(b.Env, corev1.EnvVar {
Name: "STEP_FINGERPRINT",
b.Env = append(b.Env, corev1.EnvVar{
Name: "STEP_FINGERPRINT",
Value: fingerprint,
})
b.Env = append(b.Env, corev1.EnvVar {
Name: "STEP_NOT_AFTER",
b.Env = append(b.Env, corev1.EnvVar{
Name: "STEP_NOT_AFTER",
Value: config.CertLifetime,
})
return b, nil
}
// mkRenewer generates a new renewer based on the template provided in Config.
func mkRenewer(config *Config) (corev1.Container) {
func mkRenewer(config *Config) corev1.Container {
r := config.Renewer
r.Env = append(r.Env, corev1.EnvVar {
Name: "STEP_CA_URL",
Value: config.CaUrl,
r.Env = append(r.Env, corev1.EnvVar{
Name: "STEP_CA_URL",
Value: config.CaURL,
})
return r
}
func addContainers(existing, new []corev1.Container, path string) (ops []PatchOperation) {
if len(existing) == 0 {
return []PatchOperation {
PatchOperation {
Op: "add",
Path: path,
Value: new,
},
}
} else {
for _, add := range new {
ops = append(ops, PatchOperation {
Op: "add",
Path: path + "/-",
Value: add,
})
}
return ops
}
}
func addVolumes(existing, new []corev1.Volume, path string) (ops []PatchOperation) {
if len(existing) == 0 {
return []PatchOperation{
PatchOperation {
{
Op: "add",
Path: path,
Value: new,
},
}
} else {
for _, add := range new {
ops = append(ops, PatchOperation {
Op: "add",
Path: path + "/-",
Value: add,
})
}
return ops
}
for _, add := range new {
ops = append(ops, PatchOperation{
Op: "add",
Path: path + "/-",
Value: add,
})
}
return ops
}
func addVolumes(existing, new []corev1.Volume, path string) (ops []PatchOperation) {
if len(existing) == 0 {
return []PatchOperation{
{
Op: "add",
Path: path,
Value: new,
},
}
}
for _, add := range new {
ops = append(ops, PatchOperation{
Op: "add",
Path: path + "/-",
Value: add,
})
}
return ops
}
func addCertsVolumeMount(volumeName string, containers []corev1.Container) (ops []PatchOperation) {
volumeMount := corev1.VolumeMount {
Name: volumeName,
volumeMount := corev1.VolumeMount{
Name: volumeName,
MountPath: volumeMountPath,
ReadOnly: true,
ReadOnly: true,
}
for i, container := range containers {
if len(container.VolumeMounts) == 0 {
ops = append(ops, PatchOperation {
ops = append(ops, PatchOperation{
Op: "add",
Path: fmt.Sprintf("/spec/containers/%v/volumeMounts", i),
Value: []corev1.VolumeMount{volumeMount},
})
} else {
ops = append(ops, PatchOperation {
ops = append(ops, PatchOperation{
Op: "add",
Path: fmt.Sprintf("/spec/containers/%v/volumeMounts/-", i),
Value: volumeMount,
@ -321,7 +321,7 @@ func addCertsVolumeMount(volumeName string, containers []corev1.Container) (ops
func addAnnotations(existing, new map[string]string) (ops []PatchOperation) {
if len(existing) == 0 {
return []PatchOperation{
PatchOperation {
{
Op: "add",
Path: "/metadata/annotations",
Value: new,
@ -330,15 +330,15 @@ func addAnnotations(existing, new map[string]string) (ops []PatchOperation) {
}
for k, v := range new {
if existing[k] == "" {
ops = append(ops, PatchOperation {
ops = append(ops, PatchOperation{
Op: "add",
Path: "/metadata/annotations/" + escapeJsonPath(k),
Path: "/metadata/annotations/" + escapeJSONPath(k),
Value: v,
})
} else {
ops = append(ops, PatchOperation {
Op: "replace",
Path: "/metadata/annotations/" + escapeJsonPath(k),
ops = append(ops, PatchOperation{
Op: "replace",
Path: "/metadata/annotations/" + escapeJSONPath(k),
Value: v,
})
}
@ -355,7 +355,7 @@ func addAnnotations(existing, new map[string]string) (ops []PatchOperation) {
// - Annotate the pod to indicate that it's been processed by this controller
// The result is a list of serialized JSONPatch objects (or an error).
func patch(pod *corev1.Pod, namespace string, config *Config, provisioner Provisioner) ([]byte, error) {
var ops[] PatchOperation
var ops []PatchOperation
commonName := pod.ObjectMeta.GetAnnotations()[admissionWebhookAnnotationKey]
renewer := mkRenewer(config)
@ -386,9 +386,9 @@ func shouldMutate(metadata *metav1.ObjectMeta) bool {
// mutated already (status key isn't set).
if annotations[admissionWebhookAnnotationKey] == "" || annotations[admissionWebhookStatusKey] == "injected" {
return false
} else {
return true
}
return true
}
// mutate takes an `AdmissionReview`, determines whether it is subject to mutation, and returns
@ -400,27 +400,27 @@ func mutate(review *v1beta1.AdmissionReview, config *Config, provisioner Provisi
var pod corev1.Pod
if err := json.Unmarshal(request.Object.Raw, &pod); err != nil {
ctxLog.WithField("error", err).Error("Error unmarshalling pod")
return &v1beta1.AdmissionResponse {
return &v1beta1.AdmissionResponse{
Allowed: false,
UID: request.UID,
Result: &metav1.Status {
Result: &metav1.Status{
Message: err.Error(),
},
}
}
ctxLog = ctxLog.WithFields(log.Fields{
"kind": request.Kind,
"operation": request.Operation,
"name": pod.Name,
"kind": request.Kind,
"operation": request.Operation,
"name": pod.Name,
"generateName": pod.GenerateName,
"namespace": request.Namespace,
"user": request.UserInfo,
"namespace": request.Namespace,
"user": request.UserInfo,
})
if !shouldMutate(&pod.ObjectMeta) {
ctxLog.WithField("annotations", pod.Annotations).Info("Skipping mutation")
return &v1beta1.AdmissionResponse {
return &v1beta1.AdmissionResponse{
Allowed: true,
UID: request.UID,
}
@ -429,20 +429,20 @@ func mutate(review *v1beta1.AdmissionReview, config *Config, provisioner Provisi
patchBytes, err := patch(&pod, request.Namespace, config, provisioner)
if err != nil {
ctxLog.WithField("error", err).Error("Error generating patch")
return &v1beta1.AdmissionResponse {
return &v1beta1.AdmissionResponse{
Allowed: false,
UID: request.UID,
Result: &metav1.Status {
Result: &metav1.Status{
Message: err.Error(),
},
}
}
ctxLog.WithField("patch", string(patchBytes)).Info("Generated patch")
return &v1beta1.AdmissionResponse {
Allowed: true,
Patch: patchBytes,
UID: request.UID,
return &v1beta1.AdmissionResponse{
Allowed: true,
Patch: patchBytes,
UID: request.UID,
PatchType: func() *v1beta1.PatchType {
pt := v1beta1.PatchTypeJSONPatch
return &pt
@ -477,17 +477,17 @@ func main() {
provisionerKid := os.Getenv("PROVISIONER_KID")
log.WithFields(log.Fields{
"provisionerName": provisionerName,
"provisionerKid": provisionerKid,
"provisionerKid": provisionerKid,
}).Info("Loaded provisioner configuration")
provisioner, err := NewProvisioner(provisionerName, provisionerKid, config.CaUrl, rootCAPath, provisionerPasswordFile)
provisioner, err := NewProvisioner(provisionerName, provisionerKid, config.CaURL, rootCAPath, provisionerPasswordFile)
if err != nil {
log.Errorf("Error loading provisioner: %v", err)
os.Exit(1)
}
log.WithFields(log.Fields{
"name": provisioner.Name(),
"kid": provisioner.Kid(),
"kid": provisioner.Kid(),
}).Info("Loaded provisioner")
namespace := os.Getenv("NAMESPACE")
@ -519,10 +519,10 @@ func main() {
}
/*
var name string
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
name = r.TLS.PeerCertificates[0].Subject.CommonName
}
var name string
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
name = r.TLS.PeerCertificates[0].Subject.CommonName
}
*/
if r.URL.Path != "/mutate" {
@ -554,12 +554,12 @@ func main() {
review := v1beta1.AdmissionReview{}
if _, _, err := deserializer.Decode(body, nil, &review); err != nil {
log.WithFields(log.Fields{
"body": body,
"body": body,
"error": err,
}).Error("Can't decode body")
response = &v1beta1.AdmissionResponse {
response = &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status {
Result: &metav1.Status{
Message: err.Error(),
},
}
@ -567,23 +567,23 @@ func main() {
response = mutate(&review, config, provisioner)
}
resp, err := json.Marshal(v1beta1.AdmissionReview {
resp, err := json.Marshal(v1beta1.AdmissionReview{
Response: response,
})
if err != nil {
log.WithFields(log.Fields{
"uid": review.Request.UID,
"uid": review.Request.UID,
"error": err,
}).Info("Marshal error")
http.Error(w, fmt.Sprintf("Marshal Error: %v", err), http.StatusInternalServerError)
} else {
log.WithFields(log.Fields{
"uid": review.Request.UID,
"uid": review.Request.UID,
"response": string(resp),
}).Info("Returning review")
if _, err := w.Write(resp); err != nil {
log.WithFields(log.Fields{
"uid": review.Request.UID,
"uid": review.Request.UID,
"error": err,
}).Info("Write error")
}

View file

@ -3,10 +3,13 @@ package main
import (
"encoding/json"
"fmt"
"path/filepath"
"time"
"github.com/pkg/errors"
"github.com/smallstep/cli/crypto/pki"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/certificates/ca"
"github.com/smallstep/cli/config"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/token"
@ -17,6 +20,8 @@ const (
tokenLifetime = 5 * time.Minute
)
// Provisioner is an authorized entity that can sign tokens necessary for
// signature requests.
type Provisioner interface {
Name() string
Kid() string
@ -26,7 +31,7 @@ type Provisioner interface {
type provisioner struct {
name string
kid string
caUrl string
caURL string
caRoot string
jwk *jose.JSONWebKey
tokenLifetime time.Duration
@ -52,13 +57,13 @@ func (p *provisioner) Token(subject string) (string, error) {
notBefore := time.Now()
notAfter := notBefore.Add(tokenLifetime)
signUrl := fmt.Sprintf("%v/1.0/sign", p.caUrl)
signURL := fmt.Sprintf("%v/1.0/sign", p.caURL)
tokOptions := []token.Options{
token.WithJWTID(jwtID),
token.WithKid(p.kid),
token.WithIssuer(p.name),
token.WithAudience(signUrl),
token.WithAudience(signURL),
token.WithValidity(notBefore, notAfter),
token.WithRootCA(p.caRoot),
}
@ -86,20 +91,20 @@ func decryptProvisionerJWK(encryptedKey, passFile string) (*jose.JSONWebKey, err
// loadProvisionerJWKByKid retrieves a provisioner key from the CA by key ID and
// decrypts it using the specified password file.
func loadProvisionerJWKByKid(kid, caUrl, caRoot, passFile string) (*jose.JSONWebKey, error) {
encrypted, err := pki.GetProvisionerKey(caUrl, caRoot, kid)
func loadProvisionerJWKByKid(kid, caURL, caRoot, passFile string) (*jose.JSONWebKey, error) {
encrypted, err := getProvisionerKey(caURL, caRoot, kid)
if err != nil {
return nil, err
}
return decryptProvisionerJWK(encrypted, passFile)
}
// loadProvisionerJWKByName retrieves the list of provisioners and encrypted key then
// returns the key of the first provisioner with a matching name that can be successfully
// decrypted with the specified password file.
func loadProvisionerJWKByName(name, caUrl, caRoot, passFile string) (key *jose.JSONWebKey, err error) {
provisioners, err := pki.GetProvisioners(caUrl, caRoot)
func loadProvisionerJWKByName(name, caURL, caRoot, passFile string) (key *jose.JSONWebKey, err error) {
provisioners, err := getProvisioners(caURL, caRoot)
if err != nil {
err = errors.Wrap(err, "error getting the provisioners")
return
@ -113,20 +118,20 @@ func loadProvisionerJWKByName(name, caUrl, caRoot, passFile string) (key *jose.J
}
}
}
return nil, errors.New(fmt.Sprintf("provisioner '%s' not found (or your password is wrong)", name))
return nil, errors.Errorf("provisioner '%s' not found (or your password is wrong)", name)
}
// NewProvisioner loads and decrypts key material from the CA for the named
// provisioner. The key identified by `kid` will be used if specified. If `kid`
// is the empty string we'll use the first key for the named provisioner that
// decrypts using `passFile`.
func NewProvisioner(name, kid, caUrl, caRoot, passFile string) (Provisioner, error) {
func NewProvisioner(name, kid, caURL, caRoot, passFile string) (Provisioner, error) {
var jwk *jose.JSONWebKey
var err error
if kid != "" {
jwk, err = loadProvisionerJWKByKid(kid, caUrl, caRoot, passFile)
jwk, err = loadProvisionerJWKByKid(kid, caURL, caRoot, passFile)
} else {
jwk, err = loadProvisionerJWKByName(name, caUrl, caRoot, passFile)
jwk, err = loadProvisionerJWKByName(name, caURL, caRoot, passFile)
}
if err != nil {
return nil, err
@ -135,9 +140,56 @@ func NewProvisioner(name, kid, caUrl, caRoot, passFile string) (Provisioner, err
return &provisioner{
name: name,
kid: jwk.KeyID,
caUrl: caUrl,
caURL: caURL,
caRoot: caRoot,
jwk: jwk,
tokenLifetime: tokenLifetime,
}, nil
}
}
// getRootCAPath returns the path where the root CA is stored based on the
// STEPPATH environment variable.
func getRootCAPath() string {
return filepath.Join(config.StepPath(), "certs", "root_ca.crt")
}
// getProvisioners returns the map of provisioners on the given CA.
func getProvisioners(caURL, rootFile string) ([]*authority.Provisioner, error) {
if len(rootFile) == 0 {
rootFile = getRootCAPath()
}
client, err := ca.NewClient(caURL, ca.WithRootFile(rootFile))
if err != nil {
return nil, err
}
cursor := ""
provisioners := []*authority.Provisioner{}
for {
resp, err := client.Provisioners(ca.WithProvisionerCursor(cursor), ca.WithProvisionerLimit(100))
if err != nil {
return nil, err
}
provisioners = append(provisioners, resp.Provisioners...)
if resp.NextCursor == "" {
return provisioners, nil
}
cursor = resp.NextCursor
}
}
// getProvisionerKey returns the encrypted provisioner key with the for the
// given kid.
func getProvisionerKey(caURL, rootFile, kid string) (string, error) {
if len(rootFile) == 0 {
rootFile = getRootCAPath()
}
client, err := ca.NewClient(caURL, ca.WithRootFile(rootFile))
if err != nil {
return "", err
}
resp, err := client.ProvisionerKey(kid)
if err != nil {
return "", err
}
return resp.Key, nil
}

View file

@ -44,7 +44,7 @@ func (r *rotator) loadCertificate(certFile, keyFile string) error {
}
r.certificate = &c
return nil
}
@ -87,8 +87,8 @@ func main() {
ClientCAs: roots,
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
PreferServerCipherSuites: true,
CipherSuites: []uint16{
PreferServerCipherSuites: true,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
},
@ -119,7 +119,7 @@ func main() {
if err != nil {
log.Println("Error loading certificate and key", err)
}
case <- done:
case <-done:
return
}
}
@ -127,7 +127,7 @@ func main() {
defer close(done)
log.Println("Listening no :443")
// Start serving HTTPS
err = srv.ListenAndServeTLS("", "")
if err != nil {