Skip to content

Commit

Permalink
Merge pull request #5 from frodopwns/micli
Browse files Browse the repository at this point in the history
managedMicli
  • Loading branch information
jananivMS authored May 8, 2020
2 parents ea15773 + 31df3ec commit 2931cb9
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 4 deletions.
156 changes: 156 additions & 0 deletions cli/cmd/createMi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package cmd

import (
"bytes"
"encoding/json"
"fmt"
"html/template"
"os"
"strings"
"time"

"os/exec"

"github.com/google/shlex"
"github.com/spf13/cobra"
)

type Config struct {
ResourceGroup string
ManagedIdentity string
ServicePrincipal string
Subscription string
ManagedIdentityClientID string `json:"clientId"`
ManagedIdentityID string `json:"id"`
}

var config Config

// createMiCmd represents the createMi command
var createMiCmd = &cobra.Command{
Use: "createMi",
Aliases: []string{"createmi", "createMI"},
Short: "Set up a new Managed Identity for use with the Azure Service Operator",
Long: `Set up a new Managed Identity for use with the Azure Service Operator:
Creates a new MI, assigns necessary roles, displays helpful follow-up commands.`,
RunE: func(cmd *cobra.Command, args []string) error {

commands := []struct {
Name string
C string
Target interface{}
}{
{
Name: "Create Managed Identity",
C: "az identity create -g {{ .ResourceGroup }} -n {{ .ManagedIdentity }} --subscription {{ .Subscription }} -o json",
Target: &config,
},
{
Name: "Assign Managed Identity Operator Role",
C: `az role assignment create --role "Managed Identity Operator" --assignee {{ .ServicePrincipal }} --scope "{{ .ManagedIdentityID }}"`,
Target: nil,
},
{
Name: "Assign Managed Identity Contributor Role",
C: `az role assignment create --role "Contributor" --assignee {{ .ManagedIdentityClientID }} --scope /subscriptions/{{ .Subscription }}`,
Target: nil,
},
}

for _, c := range commands {
fmt.Println("Starting action:", c.Name)
fmt.Println("-------------------------")
t := template.Must(template.New(c.Name).Parse(c.C))

var rendered bytes.Buffer
err := t.Execute(&rendered, config)
if err != nil {
return err
}

fmt.Println(rendered.String())
fmt.Println()
fmt.Println()

for {
out, err := RunCommand(rendered.String())
fmt.Println(string(out))
if err != nil {
if strings.Contains(string(out), "No matches in graph database") || strings.Contains(string(out), "does not exist in the directory") || strings.Contains(string(out), "Cannot find user or service principal in graph database"){
time.Sleep(10 * time.Second)
continue
}
return err
}

if c.Target != nil {
err = json.Unmarshal(out, c.Target)
if err != nil {
return err
}
}

break
}

}

fmt.Println()
fmt.Println("Install AAD Pod Identity:")
fmt.Println("make install-aad-pod-identity")
fmt.Println()

tpl := `apiVersion: "aadpodidentity.k8s.io/v1"
kind: AzureIdentity
metadata:
name: {{ .ManagedIdentity }}
namespace: azureoperator-system
spec:
type: 0
resourceID: /subscriptions/{{ .Subscription }}/resourcegroups/{{ .ResourceGroup }}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{{ .ManagedIdentity }}
clientID: {{ .ManagedIdentityClientID }}
---
apiVersion: "aadpodidentity.k8s.io/v1"
kind: AzureIdentityBinding
metadata:
name: aso-identity-binding
namespace: azureoperator-system
spec:
azureIdentity: {{ .ManagedIdentity }}
selector: aso_manager_binding
`

fmt.Println("cat <<EOF | kubectl apply -f -")
t := template.Must(template.New("manifests").Parse(tpl))
err := t.Execute(os.Stdout, config)
if err != nil {
return err
}
fmt.Println("EOF")

return nil
},
}

func init() {
rootCmd.AddCommand(createMiCmd)
createMiCmd.PersistentFlags().StringVarP(&config.ResourceGroup, "resource-group", "g", "", "resource group to associate managed identity with")
createMiCmd.PersistentFlags().StringVarP(&config.ManagedIdentity, "managed-identity", "i", "", "managed identity name to create and set up")
createMiCmd.PersistentFlags().StringVarP(&config.ServicePrincipal, "service-principal", "p", "", "service principal associated with kube cluster cluster")
createMiCmd.PersistentFlags().StringVarP(&config.Subscription, "subscription", "s", "", "azure subscription to act against")
}

func RunCommand(c string) ([]byte, error) {
parts, err := shlex.Split(c)
if err != nil {
return []byte(""), err
}

stmt := exec.Command(parts[0], parts[1:]...)
out, err := stmt.CombinedOutput()
return out, err
}
74 changes: 74 additions & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"

homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
)

var cfgFile string

var rootCmd = &cobra.Command{
Use: "cli",
Short: "A collection of helpers for the ASO project",
Long: `This CLI tool contains helper commands for developing/testing the ASO project.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

func init() {
cobra.OnInitialize(initConfig)

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.

rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cli.yaml)")

// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}

// Search config in home directory with name ".cli" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".cli")
}

viper.AutomaticEnv() // read in environment variables that match

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
10 changes: 10 additions & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package main

import "github.com/Azure/azure-service-operator/cli/cmd"

func main() {
cmd.Execute()
}
17 changes: 13 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,33 @@ require (
github.com/Azure/go-autorest/autorest/validation v0.1.0
github.com/Azure/go-autorest/tracing v0.1.0
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-logr/logr v0.1.0
github.com/gobuffalo/envy v1.7.0
github.com/google/go-cmp v0.3.0
github.com/google/gofuzz v1.0.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.1.1
github.com/googleapis/gnostic v0.3.0 // indirect
github.com/hashicorp/go-multierror v1.0.0
github.com/marstr/randname v0.0.0-20181206212954-d5b0f288ab8c
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.0 // indirect
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.7.0
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/prometheus/client_golang v0.9.3
github.com/satori/go.uuid v1.2.0
github.com/sethvargo/go-password v0.1.2
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.0.0
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.3
github.com/stretchr/testify v1.5.1
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
golang.org/x/sys v0.0.0-20190621203818-d432491b9138 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
gopkg.in/ini.v1 v1.55.0 // indirect
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
Expand Down
Loading

0 comments on commit 2931cb9

Please sign in to comment.