Fix dependency and linter errors.
This commit is contained in:
parent
0eb0c3a21b
commit
852f4ed564
10 changed files with 338 additions and 143 deletions
154
Gopkg.lock
generated
154
Gopkg.lock
generated
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
Loading…
Reference in a new issue