mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 06:54:01 +00:00
Add key generation.
This commit is contained in:
parent
30a89968a4
commit
5115fd5703
@ -357,6 +357,11 @@ func (s *APIServer) Run(_ []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
var installSSH master.InstallSSHKey
|
||||
instances, supported := cloud.Instances()
|
||||
if supported {
|
||||
installSSH = instances.AddSSHKeyToAllInstances
|
||||
}
|
||||
config := &master.Config{
|
||||
EtcdHelper: helper,
|
||||
EventTTL: s.EventTTL,
|
||||
@ -384,6 +389,7 @@ func (s *APIServer) Run(_ []string) error {
|
||||
MinRequestTimeout: s.MinRequestTimeout,
|
||||
SSHUser: s.SSHUser,
|
||||
SSHKeyfile: s.SSHKeyfile,
|
||||
InstallSSHKey: installSSH,
|
||||
}
|
||||
m := master.New(config)
|
||||
|
||||
|
@ -230,6 +230,10 @@ func newEc2Filter(name string, value string) *ec2.Filter {
|
||||
return filter
|
||||
}
|
||||
|
||||
func (self *AWSCloud) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
// Implementation of EC2.Instances
|
||||
func (self *awsSdkEC2) DescribeInstances(request *ec2.DescribeInstancesInput) ([]*ec2.Instance, error) {
|
||||
// Instances are paged
|
||||
|
@ -108,6 +108,9 @@ type Instances interface {
|
||||
List(filter string) ([]string, error)
|
||||
// GetNodeResources gets the resources for a particular node
|
||||
GetNodeResources(name string) (*api.NodeResources, error)
|
||||
// AddSSHKeyToAllInstances adds an SSH public key as a legal identity for all instances
|
||||
// expected format for the key is standard ssh-keygen format: <protocol> <blob>
|
||||
AddSSHKeyToAllInstances(user string, keyData []byte) error
|
||||
}
|
||||
|
||||
// Route is a representation of an advanced routing rule.
|
||||
|
@ -144,6 +144,10 @@ func (f *FakeCloud) EnsureTCPLoadBalancerDeleted(name, region string) error {
|
||||
return f.Err
|
||||
}
|
||||
|
||||
func (f *FakeCloud) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
// NodeAddresses is a test-spy implementation of Instances.NodeAddresses.
|
||||
// It adds an entry "node-addresses" into the internal method call record.
|
||||
func (f *FakeCloud) NodeAddresses(instance string) ([]api.NodeAddress, error) {
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -474,6 +475,39 @@ func (gce *GCECloud) getInstanceByName(name string) (*compute.Instance, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (gce *GCECloud) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
project, err := gce.service.Projects.Get(gce.projectID).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found := false
|
||||
for _, item := range project.CommonInstanceMetadata.Items {
|
||||
if item.Key == "sshKeys" {
|
||||
item.Value = fmt.Sprintf("%s\n%s:%s %s@%s", item.Value, user, string(keyData), user, hostname)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
// This is super unlikely, so log.
|
||||
glog.Infof("Failed to find sshKeys metadata, creating a new item")
|
||||
project.CommonInstanceMetadata.Items = append(project.CommonInstanceMetadata.Items,
|
||||
&compute.MetadataItems{
|
||||
Key: "sshKeys",
|
||||
Value: fmt.Sprint("%s:%s %s@%s", user, string(keyData), user, hostname),
|
||||
})
|
||||
}
|
||||
op, err := gce.service.Projects.SetCommonInstanceMetadata(gce.projectID, project.CommonInstanceMetadata).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return gce.waitForGlobalOp(op)
|
||||
}
|
||||
|
||||
// NodeAddresses is an implementation of Instances.NodeAddresses.
|
||||
func (gce *GCECloud) NodeAddresses(_ string) ([]api.NodeAddress, error) {
|
||||
externalIP, err := gce.metadataAccess(EXTERNAL_IP_METADATA_URL)
|
||||
|
@ -78,6 +78,10 @@ func newMesosCloud(configReader io.Reader) (*MesosCloud, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MesosCloud) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
// Instances returns a copy of the Mesos cloud Instances implementation.
|
||||
// Mesos natively provides minimal cloud-type resources. More robust cloud
|
||||
// support requires a combination of Mesos and cloud-specific knowledge.
|
||||
|
@ -317,6 +317,10 @@ func getAddressByName(api *gophercloud.ServiceClient, name string) (string, erro
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (i *Instances) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (i *Instances) NodeAddresses(name string) ([]api.NodeAddress, error) {
|
||||
glog.V(4).Infof("NodeAddresses(%v) called", name)
|
||||
|
||||
|
@ -18,6 +18,7 @@ package ovirt_cloud
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -273,3 +274,7 @@ func (v *OVirtCloud) List(filter string) ([]string, error) {
|
||||
func (v *OVirtCloud) GetNodeResources(name string) (*api.NodeResources, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (v *OVirtCloud) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
@ -376,6 +376,10 @@ func (i *Instances) InstanceID(name string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (i *Instances) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (i *Instances) GetNodeResources(name string) (*api.NodeResources, error) {
|
||||
glog.V(2).Infof("GetNodeResources(%v) called", name)
|
||||
|
||||
|
@ -131,6 +131,10 @@ func (v *VagrantCloud) getInstanceByAddress(address string) (*SaltMinion, error)
|
||||
return nil, fmt.Errorf("unable to find instance for address: %s", address)
|
||||
}
|
||||
|
||||
func (v *VagrantCloud) AddSSHKeyToAllInstances(user string, keyData []byte) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
// NodeAddresses returns the NodeAddresses of a particular machine instance.
|
||||
func (v *VagrantCloud) NodeAddresses(instance string) ([]api.NodeAddress, error) {
|
||||
// Due to vagrant not running with a dedicated DNS setup, we return the IP address of a minion as its hostname at this time
|
||||
|
@ -18,7 +18,9 @@ package master
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
@ -147,10 +149,13 @@ type Config struct {
|
||||
ServiceNodePortRange util.PortRange
|
||||
|
||||
// Used for secure proxy. If empty, don't use secure proxy.
|
||||
SSHUser string
|
||||
SSHKeyfile string
|
||||
SSHUser string
|
||||
SSHKeyfile string
|
||||
InstallSSHKey InstallSSHKey
|
||||
}
|
||||
|
||||
type InstallSSHKey func(user string, data []byte) error
|
||||
|
||||
// Master contains state for a Kubernetes cluster master/api server.
|
||||
type Master struct {
|
||||
// "Inputs", Copied from Config
|
||||
@ -204,7 +209,8 @@ type Master struct {
|
||||
InsecureHandler http.Handler
|
||||
|
||||
// Used for secure proxy
|
||||
tunnels util.SSHTunnelList
|
||||
tunnels util.SSHTunnelList
|
||||
installSSHKey InstallSSHKey
|
||||
}
|
||||
|
||||
// NewEtcdHelper returns an EtcdHelper for the provided arguments or an error if the version
|
||||
@ -486,6 +492,16 @@ func (m *Master) init(c *Config) {
|
||||
var proxyDialer func(net, addr string) (net.Conn, error)
|
||||
if len(c.SSHUser) > 0 {
|
||||
glog.Infof("Setting up proxy: %s %s", c.SSHUser, c.SSHKeyfile)
|
||||
exists, err := util.FileExists(c.SSHKeyfile)
|
||||
if err != nil {
|
||||
glog.Errorf("Error detecting if key exists: %v", err)
|
||||
} else if !exists {
|
||||
glog.Infof("Key doesn't exist, attempting to create")
|
||||
err := m.generateSSHKey(c.SSHUser, c.SSHKeyfile)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to create key pair: %v", err)
|
||||
}
|
||||
}
|
||||
m.setupSecureProxy(c.SSHUser, c.SSHKeyfile)
|
||||
proxyDialer = m.Dial
|
||||
}
|
||||
@ -801,3 +817,21 @@ func (m *Master) setupSecureProxy(user, keyfile string) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *Master) generateSSHKey(user, keyfile string) error {
|
||||
if m.installSSHKey == nil {
|
||||
return errors.New("ssh install function is null")
|
||||
}
|
||||
|
||||
private, public, err := util.GenerateKey(2048)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ioutil.WriteFile(keyfile, util.EncodePrivateKey(private), 0600)
|
||||
data, err := util.EncodeSSHKey(public)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("FOO: %s", data)
|
||||
return m.installSSHKey(user, data)
|
||||
}
|
||||
|
@ -18,10 +18,14 @@ package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
@ -260,7 +264,7 @@ func (l SSHTunnelList) Dial(network, addr string) (net.Conn, error) {
|
||||
if len(l) == 0 {
|
||||
return nil, fmt.Errorf("Empty tunnel list.")
|
||||
}
|
||||
return l[rand.Int()%len(l)].Tunnel.Dial(network, addr)
|
||||
return l[mathrand.Int()%len(l)].Tunnel.Dial(network, addr)
|
||||
}
|
||||
|
||||
func (l SSHTunnelList) Has(addr string) bool {
|
||||
@ -271,3 +275,38 @@ func (l SSHTunnelList) Has(addr string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func EncodePrivateKey(private *rsa.PrivateKey) []byte {
|
||||
return pem.EncodeToMemory(&pem.Block{
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(private),
|
||||
Type: "RSA PRIVATE KEY",
|
||||
})
|
||||
}
|
||||
|
||||
func EncodePublicKey(public *rsa.PublicKey) ([]byte, error) {
|
||||
publicBytes, err := x509.MarshalPKIXPublicKey(public)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pem.EncodeToMemory(&pem.Block{
|
||||
Bytes: publicBytes,
|
||||
Type: "PUBLIC KEY",
|
||||
}), nil
|
||||
}
|
||||
|
||||
func EncodeSSHKey(public *rsa.PublicKey) ([]byte, error) {
|
||||
publicKey, err := ssh.NewPublicKey(public)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ssh.MarshalAuthorizedKey(publicKey), nil
|
||||
}
|
||||
|
||||
func GenerateKey(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
private, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return private, &private.PublicKey, nil
|
||||
}
|
||||
|
@ -515,4 +515,16 @@ func ShortenString(str string, n int) string {
|
||||
} else {
|
||||
return str[:n]
|
||||
}
|
||||
|
||||
func FileExists(filename string) (bool, error) {
|
||||
file, err := os.Open(filename)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user