mirror of https://github.com/kubernetes/kops.git
Move ssh key functions to pkg/pki
Preparation for reuse by the roundtrip mock tests.
This commit is contained in:
parent
b6eededf7c
commit
f8c57c2f57
|
|
@ -30,6 +30,7 @@ go_library(
|
|||
"//pkg/model/components:go_default_library",
|
||||
"//pkg/model/iam:go_default_library",
|
||||
"//pkg/model/resources:go_default_library",
|
||||
"//pkg/pki:go_default_library",
|
||||
"//pkg/tokens:go_default_library",
|
||||
"//upup/pkg/fi:go_default_library",
|
||||
"//upup/pkg/fi/cloudup/awstasks:go_default_library",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
|
||||
)
|
||||
|
||||
|
|
@ -126,7 +128,7 @@ func (c *KopsModelContext) SSHKeyName() (string, error) {
|
|||
return name, nil
|
||||
}
|
||||
|
||||
fingerprint, err := awstasks.ComputeOpenSSHKeyFingerprint(string(c.SSHPublicKeys[0]))
|
||||
fingerprint, err := pki.ComputeOpenSSHKeyFingerprint(string(c.SSHPublicKeys[0]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@ go_library(
|
|||
"certificate.go",
|
||||
"csr.go",
|
||||
"privatekey.go",
|
||||
"sshkey.go",
|
||||
],
|
||||
importpath = "k8s.io/kops/pkg/pki",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/golang/glog:go_default_library"],
|
||||
deps = [
|
||||
"//upup/pkg/fi/utils:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/golang.org/x/crypto/ssh:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
|
|
@ -17,6 +22,7 @@ go_test(
|
|||
srcs = [
|
||||
"certificate_test.go",
|
||||
"privatekey_test.go",
|
||||
"sshkey_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pki
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/md5"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"k8s.io/kops/upup/pkg/fi/utils"
|
||||
)
|
||||
|
||||
// parseSSHPublicKey parses the SSH public key string
|
||||
func parseSSHPublicKey(publicKey string) (ssh.PublicKey, error) {
|
||||
tokens := strings.Fields(publicKey)
|
||||
if len(tokens) < 2 {
|
||||
return nil, fmt.Errorf("error parsing SSH public key: %q", publicKey)
|
||||
}
|
||||
|
||||
sshPublicKeyBytes, err := base64.StdEncoding.DecodeString(tokens[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding SSH public key: %q err: %s", publicKey, err)
|
||||
}
|
||||
if len(tokens) < 2 {
|
||||
return nil, fmt.Errorf("error decoding SSH public key: %q", publicKey)
|
||||
}
|
||||
|
||||
sshPublicKey, err := ssh.ParsePublicKey(sshPublicKeyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SSH public key: %v", err)
|
||||
}
|
||||
return sshPublicKey, nil
|
||||
}
|
||||
|
||||
// colonSeparatedHex formats the byte slice SSH-fingerprint style: hex bytes separated by colons
|
||||
func colonSeparatedHex(data []byte) string {
|
||||
sshKeyFingerprint := fmt.Sprintf("%x", data)
|
||||
var colonSeparated bytes.Buffer
|
||||
for i := 0; i < len(sshKeyFingerprint); i++ {
|
||||
if (i%2) == 0 && i != 0 {
|
||||
colonSeparated.WriteByte(':')
|
||||
}
|
||||
colonSeparated.WriteByte(sshKeyFingerprint[i])
|
||||
}
|
||||
|
||||
return colonSeparated.String()
|
||||
}
|
||||
|
||||
// ComputeAWSKeyFingerprint computes the AWS-specific fingerprint of the SSH public key
|
||||
func ComputeAWSKeyFingerprint(publicKey string) (string, error) {
|
||||
sshPublicKey, err := parseSSHPublicKey(publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
der, err := toDER(sshPublicKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error computing fingerprint for SSH public key: %v", err)
|
||||
}
|
||||
h := md5.Sum(der)
|
||||
|
||||
return colonSeparatedHex(h[:]), nil
|
||||
}
|
||||
|
||||
// ComputeOpenSSHKeyFingerprint computes the OpenSSH fingerprint of the SSH public key
|
||||
func ComputeOpenSSHKeyFingerprint(publicKey string) (string, error) {
|
||||
sshPublicKey, err := parseSSHPublicKey(publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
h := md5.Sum(sshPublicKey.Marshal())
|
||||
return colonSeparatedHex(h[:]), nil
|
||||
}
|
||||
|
||||
// toDER gets the DER encoding of the SSH public key
|
||||
// Annoyingly, the ssh code wraps the actual crypto keys, so we have to use reflection tricks
|
||||
func toDER(pubkey ssh.PublicKey) ([]byte, error) {
|
||||
pubkeyValue := reflect.ValueOf(pubkey)
|
||||
typeName := utils.BuildTypeName(pubkeyValue.Type())
|
||||
|
||||
var cryptoKey crypto.PublicKey
|
||||
switch typeName {
|
||||
case "*rsaPublicKey":
|
||||
var rsaPublicKey *rsa.PublicKey
|
||||
targetType := reflect.ValueOf(rsaPublicKey).Type()
|
||||
rsaPublicKey = pubkeyValue.Convert(targetType).Interface().(*rsa.PublicKey)
|
||||
cryptoKey = rsaPublicKey
|
||||
|
||||
//case "*dsaPublicKey":
|
||||
// var dsaPublicKey *dsa.PublicKey
|
||||
// targetType := reflect.ValueOf(dsaPublicKey).Type()
|
||||
// dsaPublicKey = pubkeyValue.Convert(targetType).Interface().(*dsa.PublicKey)
|
||||
// cryptoKey = dsaPublicKey
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Unexpected type of SSH key (%q); AWS can only import RSA keys", typeName)
|
||||
}
|
||||
|
||||
der, err := x509.MarshalPKIXPublicKey(cryptoKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshalling SSH public key: %v", err)
|
||||
}
|
||||
return der, nil
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package awstasks
|
||||
package pki
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -23,7 +23,7 @@ import (
|
|||
)
|
||||
|
||||
func checkAWSFingerprintEqual(t *testing.T, publicKey string, fingerprint string) {
|
||||
actual, err := computeAWSKeyFingerprint(publicKey)
|
||||
actual, err := ComputeAWSKeyFingerprint(publicKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error computing AWS key fingerprint: %v", err)
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ func checkAWSFingerprintEqual(t *testing.T, publicKey string, fingerprint string
|
|||
}
|
||||
|
||||
func checkAWSFingerprintError(t *testing.T, publicKey string, message string) {
|
||||
_, err := computeAWSKeyFingerprint(publicKey)
|
||||
_, err := ComputeAWSKeyFingerprint(publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error %q computing AWS key fingerprint", message)
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ go_library(
|
|||
deps = [
|
||||
"//pkg/diff:go_default_library",
|
||||
"//pkg/featureflag:go_default_library",
|
||||
"//pkg/pki:go_default_library",
|
||||
"//upup/pkg/fi:go_default_library",
|
||||
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
||||
"//upup/pkg/fi/cloudup/cloudformation:go_default_library",
|
||||
|
|
@ -80,7 +81,6 @@ go_library(
|
|||
"//vendor/github.com/aws/aws-sdk-go/service/iam:go_default_library",
|
||||
"//vendor/github.com/aws/aws-sdk-go/service/route53:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/golang.org/x/crypto/ssh:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
|
|
@ -94,7 +94,6 @@ go_test(
|
|||
"elastic_ip_test.go",
|
||||
"internetgateway_test.go",
|
||||
"securitygroup_test.go",
|
||||
"sshkey_test.go",
|
||||
"subnet_test.go",
|
||||
"vpc_test.go",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -17,25 +17,18 @@ limitations under the License.
|
|||
package awstasks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/md5"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/cloudformation"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
|
||||
"k8s.io/kops/upup/pkg/fi/utils"
|
||||
)
|
||||
|
||||
//go:generate fitask -type=SSHKey
|
||||
|
|
@ -102,100 +95,6 @@ func (e *SSHKey) find(cloud awsup.AWSCloud) (*SSHKey, error) {
|
|||
return actual, nil
|
||||
}
|
||||
|
||||
// parseSSHPublicKey parses the SSH public key string
|
||||
func parseSSHPublicKey(publicKey string) (ssh.PublicKey, error) {
|
||||
tokens := strings.Fields(publicKey)
|
||||
if len(tokens) < 2 {
|
||||
return nil, fmt.Errorf("error parsing SSH public key: %q", publicKey)
|
||||
}
|
||||
|
||||
sshPublicKeyBytes, err := base64.StdEncoding.DecodeString(tokens[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding SSH public key: %q err: %s", publicKey, err)
|
||||
}
|
||||
if len(tokens) < 2 {
|
||||
return nil, fmt.Errorf("error decoding SSH public key: %q", publicKey)
|
||||
}
|
||||
|
||||
sshPublicKey, err := ssh.ParsePublicKey(sshPublicKeyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SSH public key: %v", err)
|
||||
}
|
||||
return sshPublicKey, nil
|
||||
}
|
||||
|
||||
// colonSeparatedHex formats the byte slice SSH-fingerprint style: hex bytes separated by colons
|
||||
func colonSeparatedHex(data []byte) string {
|
||||
sshKeyFingerprint := fmt.Sprintf("%x", data)
|
||||
var colonSeparated bytes.Buffer
|
||||
for i := 0; i < len(sshKeyFingerprint); i++ {
|
||||
if (i%2) == 0 && i != 0 {
|
||||
colonSeparated.WriteByte(':')
|
||||
}
|
||||
colonSeparated.WriteByte(sshKeyFingerprint[i])
|
||||
}
|
||||
|
||||
return colonSeparated.String()
|
||||
}
|
||||
|
||||
// computeAWSKeyFingerprint computes the AWS-specific fingerprint of the SSH public key
|
||||
func computeAWSKeyFingerprint(publicKey string) (string, error) {
|
||||
sshPublicKey, err := parseSSHPublicKey(publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
der, err := toDER(sshPublicKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error computing fingerprint for SSH public key: %v", err)
|
||||
}
|
||||
h := md5.Sum(der)
|
||||
|
||||
return colonSeparatedHex(h[:]), nil
|
||||
}
|
||||
|
||||
// ComputeOpenSSHKeyFingerprint computes the OpenSSH fingerprint of the SSH public key
|
||||
func ComputeOpenSSHKeyFingerprint(publicKey string) (string, error) {
|
||||
sshPublicKey, err := parseSSHPublicKey(publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
h := md5.Sum(sshPublicKey.Marshal())
|
||||
return colonSeparatedHex(h[:]), nil
|
||||
}
|
||||
|
||||
// toDER gets the DER encoding of the SSH public key
|
||||
// Annoyingly, the ssh code wraps the actual crypto keys, so we have to use reflection tricks
|
||||
func toDER(pubkey ssh.PublicKey) ([]byte, error) {
|
||||
pubkeyValue := reflect.ValueOf(pubkey)
|
||||
typeName := utils.BuildTypeName(pubkeyValue.Type())
|
||||
|
||||
var cryptoKey crypto.PublicKey
|
||||
switch typeName {
|
||||
case "*rsaPublicKey":
|
||||
var rsaPublicKey *rsa.PublicKey
|
||||
targetType := reflect.ValueOf(rsaPublicKey).Type()
|
||||
rsaPublicKey = pubkeyValue.Convert(targetType).Interface().(*rsa.PublicKey)
|
||||
cryptoKey = rsaPublicKey
|
||||
|
||||
//case "*dsaPublicKey":
|
||||
// var dsaPublicKey *dsa.PublicKey
|
||||
// targetType := reflect.ValueOf(dsaPublicKey).Type()
|
||||
// dsaPublicKey = pubkeyValue.Convert(targetType).Interface().(*dsa.PublicKey)
|
||||
// cryptoKey = dsaPublicKey
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Unexpected type of SSH key (%q); AWS can only import RSA keys", typeName)
|
||||
}
|
||||
|
||||
der, err := x509.MarshalPKIXPublicKey(cryptoKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshalling SSH public key: %v", err)
|
||||
}
|
||||
return der, nil
|
||||
}
|
||||
|
||||
func (e *SSHKey) Run(c *fi.Context) error {
|
||||
if e.KeyFingerprint == nil && e.PublicKey != nil {
|
||||
publicKey, err := e.PublicKey.AsString()
|
||||
|
|
@ -203,7 +102,7 @@ func (e *SSHKey) Run(c *fi.Context) error {
|
|||
return fmt.Errorf("error reading SSH public key: %v", err)
|
||||
}
|
||||
|
||||
keyFingerprint, err := computeAWSKeyFingerprint(publicKey)
|
||||
keyFingerprint, err := pki.ComputeAWSKeyFingerprint(publicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error computing key fingerprint for SSH key: %v", err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue