blob: f1ef292dee101db25e9d161ab0f5a0f21919c521 [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001/*
2Copyright 2019 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package cert
18
19import (
20 "crypto/tls"
21 "crypto/x509"
22 "fmt"
23 "net/url"
24 "strings"
25)
26
27// GetClientCANames gets the CA names for client certs that a server accepts. This is useful when inspecting the
28// state of particular servers. apiHost is "host:port"
29func GetClientCANames(apiHost string) ([]string, error) {
30 // when we run this the second time, we know which one we are expecting
31 acceptableCAs := []string{}
32 tlsConfig := &tls.Config{
33 InsecureSkipVerify: true, // this is insecure to always get to the GetClientCertificate
34 GetClientCertificate: func(hello *tls.CertificateRequestInfo) (*tls.Certificate, error) {
35 acceptableCAs = []string{}
36 for _, curr := range hello.AcceptableCAs {
37 acceptableCAs = append(acceptableCAs, string(curr))
38 }
39 return &tls.Certificate{}, nil
40 },
41 }
42
43 conn, err := tls.Dial("tcp", apiHost, tlsConfig)
44 if err != nil {
45 return nil, err
46 }
47 if err := conn.Close(); err != nil {
48 return nil, err
49 }
50
51 return acceptableCAs, nil
52}
53
54// GetClientCANamesForURL is GetClientCANames against a URL string like we use in kubeconfigs
55func GetClientCANamesForURL(kubeConfigURL string) ([]string, error) {
56 apiserverURL, err := url.Parse(kubeConfigURL)
57 if err != nil {
58 return nil, err
59 }
60 return GetClientCANames(apiserverURL.Host)
61}
62
63// GetServingCertificates returns the x509 certs used by a server as certificates and pem encoded bytes.
64// The serverName is optional for specifying a different name to get SNI certificates. apiHost is "host:port"
65func GetServingCertificates(apiHost, serverName string) ([]*x509.Certificate, [][]byte, error) {
66 tlsConfig := &tls.Config{
67 InsecureSkipVerify: true, // this is insecure so that we always get connected
68 }
69 // if a name is specified for SNI, set it.
70 if len(serverName) > 0 {
71 tlsConfig.ServerName = serverName
72 }
73
74 conn, err := tls.Dial("tcp", apiHost, tlsConfig)
75 if err != nil {
76 return nil, nil, err
77 }
78 if err = conn.Close(); err != nil {
79 return nil, nil, fmt.Errorf("failed to close connection : %v", err)
80 }
81
82 peerCerts := conn.ConnectionState().PeerCertificates
83 peerCertBytes := [][]byte{}
84 for _, a := range peerCerts {
85 actualCert, err := EncodeCertificates(a)
86 if err != nil {
87 return nil, nil, err
88 }
89 peerCertBytes = append(peerCertBytes, []byte(strings.TrimSpace(string(actualCert))))
90 }
91
92 return peerCerts, peerCertBytes, err
93}
94
95// GetServingCertificatesForURL is GetServingCertificates against a URL string like we use in kubeconfigs
96func GetServingCertificatesForURL(kubeConfigURL, serverName string) ([]*x509.Certificate, [][]byte, error) {
97 apiserverURL, err := url.Parse(kubeConfigURL)
98 if err != nil {
99 return nil, nil, err
100 }
101 return GetServingCertificates(apiserverURL.Host, serverName)
102}