Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

non operator able to target and ssh node through bastion host #263

Merged
merged 1 commit into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion pkg/cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ func downloadTerraformFiles(option string) string {
namespace := ""
var target Target
ReadTarget(pathTarget, &target)
// return path allow non operator download key file
if getRole() == "user" {
gardenName := target.Stack()[0].Name
projectName := target.Stack()[1].Name
shootName := target.Stack()[2].Name
pathTerraform := filepath.Join(pathGardenHome, "cache", gardenName, "projects", projectName, shootName)
return filepath.Join(pathGardenHome, pathTerraform)
}

var err error
Client, err = clientToTarget("garden")
checkError(err)
Expand Down Expand Up @@ -132,7 +141,7 @@ func downloadTerraformFiles(option string) string {
checkError(err)
err = ioutil.WriteFile(filepath.Join(pathGardenHome, pathTerraform, "terraform.tfvars"), []byte(secret.Data["terraform.tfvars"]), 0644)
checkError(err)
return (filepath.Join(pathGardenHome, pathTerraform))
return filepath.Join(pathGardenHome, pathTerraform)
}

func downloadLogs(option string) {
Expand Down
59 changes: 32 additions & 27 deletions pkg/cmd/miscellaneous.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package cmd

import (
"bufio"
"errors"
"flag"
"fmt"
Expand Down Expand Up @@ -118,32 +117,6 @@ func clientToTarget(target TargetKind) (*k8s.Clientset, error) {
return clientset, err
}

// getShootClusterName returns the clustername of the shoot cluster
func getShootClusterName() (clustername string) {
clustername = ""
file, _ := os.Open(getKubeConfigOfCurrentTarget())
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "current-context:") {
clustername = strings.TrimPrefix(scanner.Text(), "current-context: ")
}
}
// retrieve full clustername
Client, err := clientToTarget("seed")
checkError(err)
namespaces, err := Client.CoreV1().Namespaces().List(metav1.ListOptions{})
checkError(err)
for _, namespace := range namespaces.Items {
if strings.HasSuffix(namespace.Name, clustername) {
clustername = namespace.Name
break
}
}
return clustername
}

// getMonitoringCredentials returns username and password required for url login to the montiring tools
func getMonitoringCredentials() (username, password string) {
var target Target
Expand Down Expand Up @@ -358,3 +331,35 @@ func getPublicIP() string {
checkError(err)
return string(ip)
}

// get role either user or operator
func getRole() string {
var role string
// will refactor in https://github.com/gardener/gardenctl/issues/266
KUBECONFIG = getKubeConfigOfClusterType("garden")
out, err := ExecCmdReturnOutput("kubectl", "--kubeconfig="+KUBECONFIG, "auth", "can-i", "get", "secret", "-A")
if err == nil {
if out == "yes" {
role = "operator"
}
} else {
role = "user"
}
return role
}

/*
getTechnicalID returns the Technical Id, which used as clustername of the shoot cluster
*/
func getTechnicalID() string {
petersutter marked this conversation as resolved.
Show resolved Hide resolved
var target Target
ReadTarget(pathTarget, &target)

gardenClientset, err := target.GardenerClient()
checkError(err)
project, err := gardenClientset.CoreV1beta1().Projects().Get(target.Stack()[1].Name, metav1.GetOptions{})
checkError(err)
shoot, err := gardenClientset.CoreV1beta1().Shoots(*project.Spec.Namespace).Get(target.Stack()[2].Name, metav1.GetOptions{})
checkError(err)
return shoot.Status.TechnicalID
}
47 changes: 24 additions & 23 deletions pkg/cmd/operate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,50 +24,51 @@ import (
openstackinstall "github.com/gardener/gardener-extension-provider-openstack/pkg/apis/openstack/install"
openstackv1alpha1 "github.com/gardener/gardener-extension-provider-openstack/pkg/apis/openstack/v1alpha1"
gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
gardencoreclientset "github.com/gardener/gardener/pkg/client/core/clientset/versioned"
"github.com/jmoiron/jsonq"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)

// operate executes a command on specified cli with pulled credentials for target
func operate(provider, arguments string) {
secretName, region := "", ""
namespaceSecret := ""
profile := ""
secretName, region, namespaceSecret, profile := "", "", "", ""
var target Target
ReadTarget(pathTarget, &target)
var err error
var secret *v1.Secret
Client, err = clientToTarget("garden")
checkError(err)
gardenClientset, err := gardencoreclientset.NewForConfig(NewConfigFromBytes(*kubeconfig))

gardenClientset, err := target.GardenerClient()
checkError(err)
shootList, err := gardenClientset.CoreV1beta1().Shoots("").List(metav1.ListOptions{})

project, err := gardenClientset.CoreV1beta1().Projects().Get(target.Stack()[1].Name, metav1.GetOptions{})
checkError(err)
for _, shoot := range shootList.Items {
if shoot.Name == target.Target[2].Name && strings.HasSuffix(shoot.Namespace, target.Target[1].Name) {
secretBindingName := shoot.Spec.SecretBindingName
region = shoot.Spec.Region
namespaceSecretBinding := shoot.Namespace
profile = shoot.Spec.CloudProfileName
secretBinding, err := gardenClientset.CoreV1beta1().SecretBindings(namespaceSecretBinding).Get((secretBindingName), metav1.GetOptions{})
checkError(err)
secretName = secretBinding.SecretRef.Name
namespaceSecret = secretBinding.SecretRef.Namespace
}
}
secret, err := Client.CoreV1().Secrets(namespaceSecret).Get((secretName), metav1.GetOptions{})
shoot, err := gardenClientset.CoreV1beta1().Shoots(*project.Spec.Namespace).Get(target.Stack()[2].Name, metav1.GetOptions{})
checkError(err)

secretBindingName := shoot.Spec.SecretBindingName
region = shoot.Spec.Region
namespaceSecretBinding := shoot.Namespace
profile = shoot.Spec.CloudProfileName

secretBinding, err := gardenClientset.CoreV1beta1().SecretBindings(namespaceSecretBinding).Get((secretBindingName), metav1.GetOptions{})
checkError(err)

secretName = secretBinding.SecretRef.Name
namespaceSecret = secretBinding.SecretRef.Namespace

secret, err = Client.CoreV1().Secrets(namespaceSecret).Get((secretName), metav1.GetOptions{})
checkError(err)

switch provider {
case "aws":
accessKeyID := []byte(secret.Data["accessKeyID"])
secretAccessKey := []byte(secret.Data["secretAccessKey"])
err := ExecCmd(nil, arguments, false, "AWS_ACCESS_KEY_ID="+string(accessKeyID[:]), "AWS_SECRET_ACCESS_KEY="+string(secretAccessKey[:]), "AWS_DEFAULT_REGION="+region, "AWS_DEFAULT_OUTPUT=text")
if err != nil {
os.Exit(2)
}
checkError(err)
case "gcp":
serviceaccount := []byte(secret.Data["serviceaccount.json"])
data := map[string]interface{}{}
Expand All @@ -76,7 +77,7 @@ func operate(provider, arguments string) {
tmpFile, err := ioutil.TempFile(os.TempDir(), "tmpFile-")
checkError(err)
defer os.Remove(tmpFile.Name())
_, err = tmpFile.Write(serviceaccount)
_, err = tmpFile.Write(serviceaccount)
checkError(err)
err = tmpFile.Close()
checkError(err)
Expand Down
8 changes: 4 additions & 4 deletions pkg/cmd/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func showVpnShoot() {
func showPrometheus() {
username, password = getMonitoringCredentials()
showPod("prometheus", "seed")
output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress prometheus -n "+getShootClusterName())
output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress prometheus -n "+getTechnicalID())
if err != nil {
fmt.Println("Cmd was unsuccessful")
os.Exit(2)
Expand All @@ -275,7 +275,7 @@ func showPrometheus() {
func showAltermanager() {
username, password = getMonitoringCredentials()
showPod("alertmanager", "seed")
output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress alertmanager -n "+getShootClusterName())
output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress alertmanager -n "+getTechnicalID())
if err != nil {
fmt.Println("Cmd was unsuccessful")
os.Exit(2)
Expand Down Expand Up @@ -352,7 +352,7 @@ func showKubernetesDashboard() {
func showGrafana() {
username, password = getMonitoringCredentials()
showPod("grafana", "seed")
output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress grafana -n "+getShootClusterName())
output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress grafana -n "+getTechnicalID())
if err != nil {
fmt.Println("Cmd was unsuccessful")
os.Exit(2)
Expand Down Expand Up @@ -382,7 +382,7 @@ func showKibana() {
if len(target.Target) == 2 {
namespace = "garden"
} else if len(target.Target) == 3 {
namespace = getShootClusterName()
namespace = getTechnicalID()
}

output, err := ExecCmdReturnOutput("bash", "-c", "export KUBECONFIG="+KUBECONFIG+"; kubectl get ingress kibana -n "+namespace)
Expand Down
34 changes: 19 additions & 15 deletions pkg/cmd/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"

gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
Expand Down Expand Up @@ -49,9 +50,7 @@ func NewSSHCmd(reader TargetReader, ioStreams IOStreams) *cobra.Command {
}

shoot, err := FetchShootFromTarget(target)
if err != nil {
return err
}
checkError(err)

if len(args) == 0 {
return printNodeNames(shoot.Name)
Expand Down Expand Up @@ -121,9 +120,7 @@ func getSSHKeypair(shoot *gardencorev1beta1.Shoot) *v1.Secret {
// printNodeNames print all nodes in k8s cluster
func printNodeNames(shootName string) error {
machineList, err := getMachineList(shootName)
if err != nil {
return err
}
checkError(err)

fmt.Println("Nodes:")
for _, machine := range machineList.Items {
Expand All @@ -147,20 +144,27 @@ echo "gardener ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/99-gardener-user
}

func getMachineList(shootName string) (*v1alpha1.MachineList, error) {
config, err := clientcmd.BuildConfigFromFlags("", getKubeConfigOfClusterType("seed"))
if err != nil {
return nil, err
if getRole() == "user" {
var target Target
ReadTarget(pathTarget, &target)
clientset, err := target.K8SClientToKind("shoot")
checkError(err)
fmt.Printf("%s\n", "Nodes")
list, _ := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
for _, node := range list.Items {
fmt.Printf("%s\n", node.Name)
}
os.Exit(0)
}

config, err := clientcmd.BuildConfigFromFlags("", getKubeConfigOfClusterType("seed"))
checkError(err)
client, err := mcmv1alpha1.NewForConfig(config)
if err != nil {
return nil, err
}
checkError(err)

shootNamespace := getSeedNamespaceNameForShoot(shootName)
machines, err := client.MachineV1alpha1().Machines(shootNamespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
checkError(err)

return machines, nil
}
4 changes: 2 additions & 2 deletions pkg/cmd/ssh_alicloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func sshToAlicloudNode(nodeName, path, user, pathSSKeypair string, sshPublicKey

// fetchAttributes gets all the needed attributes for creating bastion host and its security group with given <nodeName>.
func (a *AliyunInstanceAttribute) fetchAttributes(nodeName string) {
a.ShootName = getShootClusterName()
a.ShootName = getTechnicalID()
var err error
a.InstanceID, err = fetchAlicloudInstanceIDByNodeName(nodeName)
checkError(err)
Expand Down Expand Up @@ -616,7 +616,7 @@ func cleanupAliyunBastionHost() {

fmt.Println("")
fmt.Println("(2/4) Fetching data from target shoot cluster")
a.ShootName = getShootClusterName()
a.ShootName = getTechnicalID()
a.BastionInstanceName = a.ShootName + "-bastion"
a.BastionSecurityGroupName = a.ShootName + "-bsg"
fmt.Println("Data fetched from target shoot cluster.")
Expand Down
47 changes: 44 additions & 3 deletions pkg/cmd/ssh_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,18 @@ func sshToAWSNode(nodeName, path, user, pathSSKeypair string, sshPublicKey []byt
fmt.Println("")

fmt.Println("(1/4) Fetching data from target shoot cluster")
a.fetchAwsAttributes(nodeName, path)

if getRole() == "user" {
a.fetchAwsAttributesByCLI(nodeName, path)
} else {
a.fetchAwsAttributes(nodeName, path)
}

fmt.Println("Data fetched from target shoot cluster.")
fmt.Println("")

fmt.Println("(2/4) Setting up bastion host security group")

a.createBastionHostSecurityGroup()
fmt.Println("")

Expand All @@ -81,7 +88,7 @@ func sshToAWSNode(nodeName, path, user, pathSSKeypair string, sshPublicKey []byt
bastionNode := user + "@" + a.BastionIP
node := user + "@" + nodeName

fmt.Print("SSH " + bastionNode + " => " + node)
fmt.Print("SSH " + bastionNode + " => " + node + "\n")
key := filepath.Join(pathSSKeypair, "key")

sshCmd := fmt.Sprintf("ssh -i " + key + " -o ConnectionAttempts=2 -o \"ProxyCommand ssh -W %%h:%%p -i " + key + " -o IdentitiesOnly=yes -o ConnectionAttempts=2 -o StrictHostKeyChecking=no " + bastionNode + "\" " + node + " -o IdentitiesOnly=yes -o StrictHostKeyChecking=no")
Expand All @@ -94,9 +101,43 @@ func sshToAWSNode(nodeName, path, user, pathSSKeypair string, sshPublicKey []byt
}
}

// fetchAwsAttributes gets all the needed attributes for creating bastion host and its security group with given <nodeName> by usering aws cli for non-operator user
func (a *AwsInstanceAttribute) fetchAwsAttributesByCLI(nodeName, path string) {
petersutter marked this conversation as resolved.
Show resolved Hide resolved
a.ShootName = getTechnicalID()
publicUtility := a.ShootName + "-public-utility-z0"
arguments := fmt.Sprintf("aws ec2 describe-subnets --filters Name=tag:Name,Values=" + publicUtility + " --query Subnets[*].SubnetId")
captured := capture()
operate("aws", arguments)
capturedOutput, err := captured()
checkError(err)
a.SubnetID = strings.Trim(capturedOutput, "\n")

arguments = fmt.Sprintf("aws ec2 describe-instances --filters Name=network-interface.private-dns-name,Values=" + nodeName + " --query Reservations[*].Instances[*].{VpcId:VpcId}")
captured = capture()
operate("aws", arguments)
capturedOutput, err = captured()
checkError(err)
a.VpcID = strings.Trim(capturedOutput, "\n")

a.SecurityGroupName = a.ShootName + "-nodes"
a.getSecurityGroupID()
a.BastionInstanceName = a.ShootName + "-bastions"
a.BastionSecurityGroupName = a.ShootName + "-bsg"

arguments = fmt.Sprintf("aws ec2 describe-instances --filters Name=network-interface.private-dns-name,Values=" + nodeName + " --query Reservations[*].Instances[*].{ImageId:ImageId}")
captured = capture()
operate("aws", arguments)
capturedOutput, err = captured()
checkError(err)
a.ImageID = strings.Trim(capturedOutput, "\n")

a.KeyName = a.ShootName + "-ssh-publickey"
a.UserData = getBastionUserData(a.SSHPublicKey)
}

// fetchAwsAttributes gets all the needed attributes for creating bastion host and its security group with given <nodeName>.
func (a *AwsInstanceAttribute) fetchAwsAttributes(nodeName, path string) {
a.ShootName = getShootClusterName()
a.ShootName = getTechnicalID()

yamlData, err := ioutil.ReadFile(path)
checkError(err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/ssh_azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func sshToAZNode(nodeName, path, user, pathSSKeypair string, sshPublicKey []byte

// fetchAttributes gets all the needed attributes for creating bastion host and its security group with given <nodeName>.
func (a *AzureInstanceAttribute) fetchAzureAttributes(nodeName, path string) {
a.ShootName = getShootClusterName()
a.ShootName = getTechnicalID()
a.NamePublicIP = "sshIP"
var err error

Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/ssh_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func sshToGCPNode(nodeName, path, user, pathSSKeypair string, sshPublicKey []byt
// fetchAttributes gets all the needed attributes for creating bastion host and its security group with given <nodeName>.
func (g *GCPInstanceAttribute) fetchGCPAttributes(nodeName, path string) {
var err error
g.ShootName = getShootClusterName()
g.ShootName = getTechnicalID()
g.BastionHostName = g.ShootName + "-bastions"
g.FirewallRuleName = g.ShootName + "-allow-ssh-access"
g.Subnetwork = g.ShootName + "-nodes"
Expand Down
Loading