diff --git a/Gopkg.lock b/Gopkg.lock index e5b3cb14..bacd9620 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -966,7 +966,7 @@ [[projects]] branch = "master" - digest = "1:18e38e0ec694fdad73da5156624020664b1950c8f919216f75896c31323eb8a7" + digest = "1:82eaafe1b10a648afe37de603c6d9f4fe69fb5c129ecc832a5997335f3a0ee89" name = "knative.dev/pkg" packages = [ "apis", @@ -986,7 +986,7 @@ "reconciler", ] pruneopts = "T" - revision = "bb008a5b533c110945aad45df24877c39bc5f792" + revision = "7af3fab62ce2bf2f861fee510eeb15eccb47925e" [[projects]] branch = "master" @@ -997,7 +997,7 @@ "tools/dep-collector", ] pruneopts = "UT" - revision = "908ad6cdb8e4aab96cdf0d94f766db7caf4fe129" + revision = "01760e2303d6a17936658f155004da3019d0f43c" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" diff --git a/vendor/knative.dev/pkg/Gopkg.lock b/vendor/knative.dev/pkg/Gopkg.lock index 1a008c57..8ec3cc89 100644 --- a/vendor/knative.dev/pkg/Gopkg.lock +++ b/vendor/knative.dev/pkg/Gopkg.lock @@ -1339,14 +1339,14 @@ [[projects]] branch = "master" - digest = "1:691951c6805590983ccea7c6dbca360bcb58af5f4d60f75af9499903bb3039e9" + digest = "1:e7ea104eff9c91ce48f1730ab8b4098faa1ea519162ccbbbca68c205428f0e21" name = "knative.dev/test-infra" packages = [ "scripts", "tools/dep-collector", ] pruneopts = "UT" - revision = "279d938f5e19db2550bea7f71f4cdb97e0d84128" + revision = "908ad6cdb8e4aab96cdf0d94f766db7caf4fe129" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" @@ -1420,6 +1420,7 @@ "google.golang.org/api/iterator", "google.golang.org/api/option", "google.golang.org/grpc", + "google.golang.org/grpc/credentials", "gopkg.in/yaml.v2", "k8s.io/api/admission/v1beta1", "k8s.io/api/admissionregistration/v1beta1", diff --git a/vendor/knative.dev/pkg/injection/sharedmain/main.go b/vendor/knative.dev/pkg/injection/sharedmain/main.go index e25a0665..83dd0d25 100644 --- a/vendor/knative.dev/pkg/injection/sharedmain/main.go +++ b/vendor/knative.dev/pkg/injection/sharedmain/main.go @@ -29,6 +29,7 @@ import ( "go.opencensus.io/stats/view" "golang.org/x/sync/errgroup" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/rest" @@ -325,13 +326,29 @@ func WatchObservabilityConfigOrDie(ctx context.Context, cmw *configmap.InformedW if _, err := kubeclient.Get(ctx).CoreV1().ConfigMaps(system.Namespace()).Get(metrics.ConfigMapName(), metav1.GetOptions{}); err == nil { cmw.Watch(metrics.ConfigMapName(), - metrics.UpdateExporterFromConfigMap(component, logger), + metrics.ConfigMapWatcher(component, SecretFetcher(ctx), logger), profilingHandler.UpdateFromConfigMap) } else if !apierrors.IsNotFound(err) { logger.With(zap.Error(err)).Fatalf("Error reading ConfigMap %q", metrics.ConfigMapName()) } } +// SecretFetcher provides a helper function to fetch individual Kubernetes +// Secrets (for example, a key for client-side TLS). Note that this is not +// intended for high-volume usage; the current use is when establishing a +// metrics client connection in WatchObservabilityConfigOrDie. +func SecretFetcher(ctx context.Context) metrics.SecretFetcher { + // NOTE: Do not use secrets.Get(ctx) here to get a SecretLister, as it will register + // a *global* SecretInformer and require cluster-level `secrets.list` permission, + // even if you scope down the Lister to a given namespace after requesting it. Instead, + // we package up a function from kubeclient. + // TODO(evankanderson): If this direct request to the apiserver on each TLS connection + // to the opencensus agent is too much load, switch to a cached Secret. + return func(name string) (*corev1.Secret, error) { + return kubeclient.Get(ctx).CoreV1().Secrets(system.Namespace()).Get(name, metav1.GetOptions{}) + } +} + // ControllersAndWebhooksFromCtors returns a list of the controllers and a list // of the webhooks created from the given constructors. func ControllersAndWebhooksFromCtors(ctx context.Context, diff --git a/vendor/knative.dev/pkg/metrics/README.md b/vendor/knative.dev/pkg/metrics/README.md index 9a5e5a08..49d3969c 100644 --- a/vendor/knative.dev/pkg/metrics/README.md +++ b/vendor/knative.dev/pkg/metrics/README.md @@ -94,8 +94,8 @@ statistics for a short period of time if not. **This is true today.** [Ensure this on an ongoing basis.](https://github.com/knative/pkg/issues/957) - [ ] Google to implement OpenCensus Agent configuration to match what they are - doing for Stackdriver now. (No public issue link because this shoud be in - Google's vendor-specific configuration.) + doing for Stackdriver now. (No public issue link because this should be + in Google's vendor-specific configuration.) - [ ] Document how to configure OpenCensus/OpenTelemetry Agent + Prometheus to achieve the current level of application visibility, and determine a long-term course for how to maintain this as a "bare minimum" supported diff --git a/vendor/knative.dev/pkg/metrics/config.go b/vendor/knative.dev/pkg/metrics/config.go index 8c24e788..1dd072d5 100644 --- a/vendor/knative.dev/pkg/metrics/config.go +++ b/vendor/knative.dev/pkg/metrics/config.go @@ -86,6 +86,10 @@ type metricsConfig struct { // writing the metrics to the stats.RecordWithOptions interface. recorder func(context.Context, []stats.Measurement, ...stats.Options) error + // secretFetcher provides access for fetching Kubernetes Secrets from an + // informer cache. + secretFetcher SecretFetcher + // ---- OpenCensus specific below ---- // collectorAddress is the address of the collector, if not `localhost:55678` collectorAddress string @@ -156,6 +160,10 @@ func (mc *metricsConfig) record(ctx context.Context, mss []stats.Measurement, ro func createMetricsConfig(ops ExporterOptions, logger *zap.SugaredLogger) (*metricsConfig, error) { var mc metricsConfig + // We don't check if this is `nil` right now, because this is a transition step. + // Eventually, this should be a startup check. + mc.secretFetcher = ops.Secrets + if ops.Domain == "" { return nil, errors.New("metrics domain cannot be empty") } diff --git a/vendor/knative.dev/pkg/metrics/exporter.go b/vendor/knative.dev/pkg/metrics/exporter.go index b34c60a9..f8c778b4 100644 --- a/vendor/knative.dev/pkg/metrics/exporter.go +++ b/vendor/knative.dev/pkg/metrics/exporter.go @@ -29,6 +29,10 @@ var ( metricsMux sync.RWMutex ) +// SecretFetcher is a function (extracted from SecretNamespaceLister) for fetching +// a specific Secret. This avoids requiring global or namespace list in controllers. +type SecretFetcher func(string) (*corev1.Secret, error) + type flushable interface { // Flush waits for metrics to be uploaded. Flush() @@ -65,17 +69,29 @@ type ExporterOptions struct { // See https://github.com/knative/serving/blob/master/config/config-observability.yaml // for details. ConfigMap map[string]string + + // A lister for Secrets to allow dynamic configuration of outgoing TLS client cert. + Secrets SecretFetcher `json:"-"` } // UpdateExporterFromConfigMap returns a helper func that can be used to update the exporter // when a config map is updated. +// DEPRECATED: Callers should migrate to ConfigMapWatcher. func UpdateExporterFromConfigMap(component string, logger *zap.SugaredLogger) func(configMap *corev1.ConfigMap) { + return ConfigMapWatcher(component, nil, logger) +} + +// ConfigMapWatcher returns a helper func which updates the exporter configuration based on +// values in the supplied ConfigMap. This method captures a corev1.SecretLister which is used +// to configure mTLS with the opencensus agent. +func ConfigMapWatcher(component string, secrets SecretFetcher, logger *zap.SugaredLogger) func(*corev1.ConfigMap) { domain := Domain() return func(configMap *corev1.ConfigMap) { UpdateExporter(ExporterOptions{ Domain: domain, Component: component, ConfigMap: configMap.Data, + Secrets: secrets, }, logger) } } diff --git a/vendor/knative.dev/pkg/metrics/opencensus_exporter.go b/vendor/knative.dev/pkg/metrics/opencensus_exporter.go index 2a947f9d..2a54f6c6 100644 --- a/vendor/knative.dev/pkg/metrics/opencensus_exporter.go +++ b/vendor/knative.dev/pkg/metrics/opencensus_exporter.go @@ -14,9 +14,14 @@ limitations under the License. package metrics import ( + "crypto/tls" + "fmt" + "contrib.go.opencensus.io/exporter/ocagent" "go.opencensus.io/stats/view" "go.uber.org/zap" + "google.golang.org/grpc/credentials" + "k8s.io/apimachinery/pkg/api/errors" ) func newOpenCensusExporter(config *metricsConfig, logger *zap.SugaredLogger) (view.Exporter, error) { @@ -24,7 +29,9 @@ func newOpenCensusExporter(config *metricsConfig, logger *zap.SugaredLogger) (vi if config.collectorAddress != "" { opts = append(opts, ocagent.WithAddress(config.collectorAddress)) } - if !config.requireSecure { + if config.requireSecure { + opts = append(opts, ocagent.WithTLSCredentials(credentialFetcher(config.component, config.secretFetcher, logger))) + } else { opts = append(opts, ocagent.WithInsecure()) } e, err := ocagent.NewExporter(opts...) @@ -36,3 +43,36 @@ func newOpenCensusExporter(config *metricsConfig, logger *zap.SugaredLogger) (vi view.RegisterExporter(e) return e, nil } + +// credentialFetcher attempts to locate a secret containing TLS credentials +// for communicating with the OpenCensus Agent. To do this, it first looks +// for a secret named "-opencensus", then for a generic +// "opencensus" secret. +func credentialFetcher(component string, lister SecretFetcher, logger *zap.SugaredLogger) credentials.TransportCredentials { + if lister == nil { + logger.Errorf("No secret lister provided for component %q; cannot use requireSecure=true", component) + return nil + } + return credentials.NewTLS(&tls.Config{ + GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { + // We ignore the CertificateRequestInfo for now, and hand back a single fixed certificate. + // TODO(evankanderson): maybe do something SPIFFE-ier? + cert, err := certificateFetcher(component+"-opencensus", lister) + if errors.IsNotFound(err) { + cert, err = certificateFetcher("opencensus", lister) + } + if err != nil { + return nil, fmt.Errorf("Unable to fetch opencensus secret for %q, cannot use requireSecure=true: %+v", component, err) + } + return &cert, err + }, + }) +} + +func certificateFetcher(secretName string, lister SecretFetcher) (tls.Certificate, error) { + secret, err := lister(secretName) + if err != nil { + return tls.Certificate{}, err + } + return tls.X509KeyPair(secret.Data["client-cert.pem"], secret.Data["client-key.pem"]) +} diff --git a/vendor/knative.dev/pkg/metrics/testdata/README.md b/vendor/knative.dev/pkg/metrics/testdata/README.md new file mode 100644 index 00000000..12444d6e --- /dev/null +++ b/vendor/knative.dev/pkg/metrics/testdata/README.md @@ -0,0 +1,14 @@ +# Test files for metrics + +The cert files were generated with: + +```shell +openssl req -x509 -nodes -newkey dsa:<(openssl dsaparam 1024) -keyout client-key.pem -out client-cert.pem -days 10000 +``` + +Note that there are some manual prompts later in the process. This seemed simpler than generating the certs in Go. + +To view the cert: +```shell +openssl x509 -noout -text -in client-cert.pem +``` diff --git a/vendor/knative.dev/pkg/metrics/testdata/client-cert.pem b/vendor/knative.dev/pkg/metrics/testdata/client-cert.pem new file mode 100644 index 00000000..6f0cacf7 --- /dev/null +++ b/vendor/knative.dev/pkg/metrics/testdata/client-cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICfDCCAjoCCQDJUTmi/6JoGDALBglghkgBZQMEAwIwIjEgMB4GA1UEAwwXdGVz +dC1jbGllbnQuZXhhbXBsZS5jb20wHhcNMjAwMjE0MTg1OTE2WhcNNDcwNzAyMTg1 +OTE2WjAiMSAwHgYDVQQDDBd0ZXN0LWNsaWVudC5leGFtcGxlLmNvbTCCAbYwggEr +BgcqhkjOOAQBMIIBHgKBgQCEMFcdoo8FsDPTY5lupaggF7LrvxEKYOKR+wSug9uk +mzreh3KtfJW2YseHUmjqafd367//Ych7gJim8UTEkdjZEfFKK8iRLTRyjNwK0KRb +1JqL4qT9wmNpsrZ90KDX3xaJukbOZHumlb5AmJXD1RGSjnSaWqLzuXxmvVVkPnhe +AwIVAMj19ML2hIr0O6cqiQg3Zmh/It/VAoGAfLoW+TmD6JAJyxtp7QMVujbP/OY+ +jV4wwekXBzgZITUWupC0ULtMY+6VLPvS6Up0mnnZxgVFnABpvoCqrc+tG1p7Lnyi +2XG9AQ1V9JMRTjerQoDGCS/kMDD7jx37N59tkq6sJ+XYFOVSjfAlRTmW6wV1DpUW +m7olKlj6mEL3qI0DgYQAAoGACz1U5FNb5ANwgcc70dvRU0PrBs9HEZd+jaH7yfBV +g9Eas6aBAx5yAHK6g3tYvI9dzVUgZZmKgEspNsjusB1cnSBBVa7YxlCKn6MZB523 +5+8KnKFMtOYMivRM19Dr+bBvvCkwOc37PJREcCrmddN1OWAM1sEinwxWINumktLO +QmkwCwYJYIZIAWUDBAMCAy8AMCwCFGjZ2Hc70n9AanALEmAaOCZ5yCJ6AhQXyIXt +4m9Fu8NFOK5qJYhxxDOp9Q== +-----END CERTIFICATE----- diff --git a/vendor/knative.dev/pkg/metrics/testdata/client-key.pem b/vendor/knative.dev/pkg/metrics/testdata/client-key.pem new file mode 100644 index 00000000..09fce9d0 --- /dev/null +++ b/vendor/knative.dev/pkg/metrics/testdata/client-key.pem @@ -0,0 +1,9 @@ +-----BEGIN PRIVATE KEY----- +MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAIQwVx2ijwWwM9NjmW6lqCAXsuu/ +EQpg4pH7BK6D26SbOt6Hcq18lbZix4dSaOpp93frv/9hyHuAmKbxRMSR2NkR8Uor +yJEtNHKM3ArQpFvUmovipP3CY2mytn3QoNffFom6Rs5ke6aVvkCYlcPVEZKOdJpa +ovO5fGa9VWQ+eF4DAhUAyPX0wvaEivQ7pyqJCDdmaH8i39UCgYB8uhb5OYPokAnL +G2ntAxW6Ns/85j6NXjDB6RcHOBkhNRa6kLRQu0xj7pUs+9LpSnSaednGBUWcAGm+ +gKqtz60bWnsufKLZcb0BDVX0kxFON6tCgMYJL+QwMPuPHfs3n22Srqwn5dgU5VKN +8CVFOZbrBXUOlRabuiUqWPqYQveojQQWAhRn0IIk7GKtluNxnlqYpCuNazN6gQ== +-----END PRIVATE KEY----- diff --git a/vendor/knative.dev/pkg/metrics/testdata/server-cert.pem b/vendor/knative.dev/pkg/metrics/testdata/server-cert.pem new file mode 100644 index 00000000..22935c1a --- /dev/null +++ b/vendor/knative.dev/pkg/metrics/testdata/server-cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICwDCCAagCCQCenPDbJ3W+6zANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBd0 +ZXN0LXNlcnZlci5leGFtcGxlLmNvbTAeFw0yMDAyMTQyMDEyMzBaFw0yMjExMTAy +MDEyMzBaMCIxIDAeBgNVBAMMF3Rlc3Qtc2VydmVyLmV4YW1wbGUuY29tMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx4OIOJdBv2mxvSI3izpUu/RL5ND5 +9IQ1hM5UDCnH2UifweWSEePXDnJgqi8563+gzQHMTN/BBNR4HiIbUulq1KDZjYKE +7FtT8PCE8XXwTxieyV/uiIlfd0b74NcSvuayKzGwOZ2h44kU/n8hZ5ubwmS1Dlir +jCcJtFK3zcqnjqhmjqgj6gZJA/v5ipEnO78+kWU37XvRAGbfaK1/NzyENozg52q7 +OhFeVci2SEvn0gE0XC0jbgKFRvaZtMEhfwkggaUYv122btHntP5/Y4iNzxllDocD +h6GxXqgbnopdrDEscEbObJc6FJtUvHtMF1lnM2SMXWdMCueUvGUFLGxAqwIDAQAB +MA0GCSqGSIb3DQEBCwUAA4IBAQBiMAv5lL+jwUgEeaVn7B9Uma3nyW3yAOce6j2/ +7ADR4KNNomEzrEJuH67FQNQQj8CkNMtjSsHEwhLrDlkE6SKhZn1ikNw36+5DDa0o +42Dzv/UrUUY0dJc1KB6Sro4K0k/ivNWHXe+cdCbqbrZk29QXUVAnBiqJ3r3VWOMG +6lgO9kV6Dr5M7RnEOtNT7Dfr7/T817vXODZqa830J8XrM6e2znSB2QVTgswQ0HTf +K3SObMYeZc76hg/yOUzdinBMRjZ/Op/a9oE5W71YS3aG/t2v8b2Z2gwIBR4Sa+cr +y4VcW99RLXlzjtTCKnVvX9sRLFBZa96Rslm0nFWzbz40umaD +-----END CERTIFICATE----- diff --git a/vendor/knative.dev/pkg/metrics/testdata/server-key.pem b/vendor/knative.dev/pkg/metrics/testdata/server-key.pem new file mode 100644 index 00000000..fe9d9006 --- /dev/null +++ b/vendor/knative.dev/pkg/metrics/testdata/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDHg4g4l0G/abG9 +IjeLOlS79Evk0Pn0hDWEzlQMKcfZSJ/B5ZIR49cOcmCqLznrf6DNAcxM38EE1Hge +IhtS6WrUoNmNgoTsW1Pw8ITxdfBPGJ7JX+6IiV93Rvvg1xK+5rIrMbA5naHjiRT+ +fyFnm5vCZLUOWKuMJwm0UrfNyqeOqGaOqCPqBkkD+/mKkSc7vz6RZTfte9EAZt9o +rX83PIQ2jODnars6EV5VyLZIS+fSATRcLSNuAoVG9pm0wSF/CSCBpRi/XbZu0ee0 +/n9jiI3PGWUOhwOHobFeqBueil2sMSxwRs5slzoUm1S8e0wXWWczZIxdZ0wK55S8 +ZQUsbECrAgMBAAECggEAIp6kSI2WjwxcFyGU2cfpZCPj93R7qv41+zGCTAoD76Q2 +dILNceVDL/KQ63b+aerfkDM7rCs3ZwsnPLNWYnC2ZOb0WSXIwuqmCizyJKP+avsu +smq/DVopAp2Cn2Uyj4WgbPZWSekcaksjJXYR6dSKlpS7Bh5ExjEP8gZYdpEvugUY +LOnenhrHJ+eGI1nQ5Sb2fuAOXyM6UYPw0H4d8s/2xwe8fzgOUO8v4PAYPnA6M/R/ +Y/p6qIuRzEuHwqYuTZ7S1g9UG5hW0HaEuMaQZM9UtK2PxfEP3WHPJZ8zjIVgLhIf +yjPWo4s9X477NURYX9R2JeoLgea5sYCgqXvsSSvA4QKBgQDpqxjP8NxC0KwtonvS +08EtUwGZaPQ9aROVBqa5u4BLyJ+YwBbBt2DlWTSKJ1eDC9olaca1/pRPxysS4N7x +CieZkFES3sS0oaLssh+BQ4VsvvkkBdsdcWAcK6Joj7uIjlEfl72hJq8mUeR14gyy +G2wE/sZ1m5wopqItGjcuR4qd5wKBgQDalNBaAcbyD1K415sh0uFCujwPoh5ezr4f +VNBUL1VaOBztOyAp7szoo/lyfMpq+6tCn1X61DtHyBJkM3fp9IpaQpc9AnHfedx4 +0iwispzkpGFY0S88HZotB3oxN9kU+Ll3/i7unXqPmbxNEEoYlZ3UJmLOiqKgdccc +qv2I+toGnQKBgDT9Vf0h8/E6/TDEHixrVO2AW2Z8xJaAk65B+eE4whltf7PWK9L2 +UQTxu9ZwoYnYUDoXyLZQ6zVER2JamHQ1B1HtxlTvK9CCrz3aDwbzVviYPkuLAGum +4FLDGmt33OFU1NTDRn+bFDEudQ6+mn5xdYeUd1EIXtthHnn37feSxb6VAoGAXLZ+ +YY8baZTiS5D4NjKSZZFE5ISpSSF8NyHsc6jYFTpz2pQXonGt7IeQyOTxnss86zdW +atwWgO32DxZdqJiXDo3sRG6DCn1P7NeI7PbB4aFvwRKJbIBJ4wum4rWDmIefc6wX +EBMv5zUYT7+3DhJ4LYJSqrTXIiSS3jAQ9kcgr2kCgYBE8W+Nx4stlLlQ3EpocikZ +D2GcFyTE0TfZf82NV9uPkDXZ8vYQQ9NEIn+crY1gC3edknMXJ5v1IUaRacxQPp2C +0UewG3HQqgybhq2wvnMrw+dJqo2vuOInDZAC/Zvv+RGXtc3H+v6o875n3TYOro67 +P4jKdY+Mxl3BLvI6KhJJrA== +-----END PRIVATE KEY-----