github.com/Azure/aad-pod-identity@v1.8.17/cmd/mic/main.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"net/http"
     6  	_ "net/http/pprof" // #nosec
     7  	"os"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/Azure/aad-pod-identity/pkg/log"
    12  	"github.com/Azure/aad-pod-identity/pkg/metrics"
    13  	"github.com/Azure/aad-pod-identity/pkg/mic"
    14  	"github.com/Azure/aad-pod-identity/pkg/probes"
    15  	"github.com/Azure/aad-pod-identity/version"
    16  
    17  	"k8s.io/client-go/rest"
    18  	"k8s.io/client-go/tools/clientcmd"
    19  	"k8s.io/klog/v2"
    20  )
    21  
    22  var (
    23  	kubeconfig                          string
    24  	cloudconfig                         string
    25  	forceNamespaced                     bool
    26  	versionInfo                         bool
    27  	syncRetryDuration                   time.Duration
    28  	leaderElectionCfg                   mic.LeaderElectionConfig
    29  	httpProbePort                       string
    30  	enableProfile                       bool
    31  	enableScaleFeatures                 bool
    32  	createDeleteBatch                   int64
    33  	clientQPS                           float64
    34  	prometheusPort                      string
    35  	immutableUserMSIs                   string
    36  	cmConfig                            mic.CMConfig
    37  	typeUpgradeConfig                   mic.TypeUpgradeConfig
    38  	updateUserMSIConfig                 mic.UpdateUserMSIConfig
    39  	identityAssignmentReconcileInterval time.Duration
    40  )
    41  
    42  func main() {
    43  	klog.InitFlags(nil)
    44  	defer klog.Flush()
    45  
    46  	logOptions := log.NewOptions()
    47  	logOptions.AddFlags()
    48  
    49  	hostName, err := os.Hostname()
    50  	if err != nil {
    51  		klog.Fatalf("failed to get hostname, error: %+v", err)
    52  	}
    53  	flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to the kube config")
    54  	flag.StringVar(&cloudconfig, "cloudconfig", "", "Path to cloud config e.g. Azure.json file")
    55  	flag.BoolVar(&forceNamespaced, "forceNamespaced", false, "Forces namespaced identities, binding, and assignment")
    56  	flag.BoolVar(&versionInfo, "version", false, "Prints the version information")
    57  	flag.DurationVar(&syncRetryDuration, "syncRetryDuration", 3600*time.Second, "The interval in seconds at which sync loop should periodically check for errors and reconcile.")
    58  
    59  	// Leader election parameters
    60  	flag.StringVar(&leaderElectionCfg.Instance, "leader-election-instance", hostName, "leader election instance name. default is 'hostname'")
    61  	flag.StringVar(&leaderElectionCfg.Namespace, "leader-election-namespace", "default", "namespace to create leader election objects")
    62  	flag.StringVar(&leaderElectionCfg.Name, "leader-election-name", "aad-pod-identity-mic", "leader election name")
    63  	flag.DurationVar(&leaderElectionCfg.Duration, "leader-election-duration", time.Second*15, "leader election duration")
    64  
    65  	// Probe port
    66  	flag.StringVar(&httpProbePort, "http-probe-port", "8080", "http liveliness probe port")
    67  
    68  	// Prometheus port
    69  	flag.StringVar(&prometheusPort, "prometheus-port", "8888", "Prometheus port for metrics")
    70  
    71  	// Profile
    72  	flag.BoolVar(&enableProfile, "enableProfile", false, "Enable/Disable pprof profiling")
    73  
    74  	// Enable scale features handles the label based azureassignedidentity.
    75  	flag.BoolVar(&enableScaleFeatures, "enableScaleFeatures", false, "Enable/Disable new features used for clusters at scale")
    76  
    77  	// createDeleteBatch can be used for tuning the number of outstanding api server operations we do per node/VMSS.
    78  	flag.Int64Var(&createDeleteBatch, "createDeleteBatch", 20, "Per node/VMSS create/delete batches")
    79  
    80  	// Client QPS is used to configure the client-go QPS throttling and bursting.
    81  	flag.Float64Var(&clientQPS, "clientQps", 5, "Client QPS used for throttling of calls to kube-api server")
    82  
    83  	// Identities that should be never removed from Azure AD (used defined managed identities)
    84  	flag.StringVar(&immutableUserMSIs, "immutable-user-msis", "", "prevent deletion of these IDs from the underlying VM/VMSS")
    85  
    86  	// Config map for aad-pod-identity
    87  	flag.StringVar(&cmConfig.Name, "config-map-name", "aad-pod-identity-config", "Configmap name")
    88  	// Config map details for the type changes in the context of client-go upgrade.
    89  	flag.StringVar(&typeUpgradeConfig.TypeUpgradeStatusKey, "type-upgrade-status-key", "type-upgrade-status", "Configmap key for type upgrade status")
    90  	flag.BoolVar(&typeUpgradeConfig.EnableTypeUpgrade, "enable-type-upgrade", true, "Enable type upgrade")
    91  
    92  	// Parameters for retrying cloudprovider's UpdateUserMSI function
    93  	flag.IntVar(&updateUserMSIConfig.MaxRetry, "update-user-msi-max-retry", 2, "The maximum retry of UpdateUserMSI call")
    94  	flag.DurationVar(&updateUserMSIConfig.RetryInterval, "update-user-msi-retry-interval", 1*time.Second, "The duration to wait before retrying UpdateUserMSI")
    95  
    96  	// Parameters for reconciling identity assignment on Azure
    97  	flag.DurationVar(&identityAssignmentReconcileInterval, "identity-assignment-reconcile-interval", 3*time.Minute, "The interval between reconciling identity assignment on Azure based on an existing list of AzureAssignedIdentities")
    98  
    99  	flag.Parse()
   100  
   101  	if err := logOptions.Apply(); err != nil {
   102  		klog.Fatalf("unable to apply logging options, error: %+v", err)
   103  	}
   104  
   105  	podns := os.Getenv("MIC_POD_NAMESPACE")
   106  	if podns == "" {
   107  		klog.Fatalf("namespace not specified. Please add meta.namespace as env variable MIC_POD_NAMESPACE")
   108  	}
   109  	cmConfig.Namespace = podns
   110  
   111  	if versionInfo {
   112  		version.PrintVersionAndExit()
   113  	}
   114  	klog.Infof("starting mic process. Version: %v. Build date: %v", version.MICVersion, version.BuildDate)
   115  	if cloudconfig == "" {
   116  		klog.Warningf("--cloudconfig not passed will use aadpodidentity-admin-secret")
   117  	}
   118  	if kubeconfig == "" {
   119  		klog.Warningf("--kubeconfig not passed will use InClusterConfig")
   120  	}
   121  	if enableProfile {
   122  		profilePort := "6060"
   123  		klog.Infof("starting profiling on port %s", profilePort)
   124  		go func() {
   125  			addr := "localhost:" + profilePort
   126  			if err := http.ListenAndServe(addr, nil); err != nil {
   127  				klog.Errorf("failed to listen and serve %s, error: %+v", addr, err)
   128  			}
   129  		}()
   130  	}
   131  
   132  	if enableScaleFeatures {
   133  		klog.Infof("enableScaleFeatures is DEPRECATED for MIC and isn't required. This flag will be removed in the next release.")
   134  	}
   135  
   136  	klog.Infof("kubeconfig (%s) cloudconfig (%s)", kubeconfig, cloudconfig)
   137  	config, err := buildConfig(kubeconfig)
   138  	if err != nil {
   139  		klog.Fatalf("failed to build config from %s, error: %+v", kubeconfig, err)
   140  	}
   141  	config.UserAgent = version.GetUserAgent("MIC", version.MICVersion)
   142  
   143  	forceNamespaced = forceNamespaced || "true" == os.Getenv("FORCENAMESPACED")
   144  	klog.Infof("running MIC in namespaced mode: %v", forceNamespaced)
   145  
   146  	config.QPS = float32(clientQPS)
   147  	config.Burst = int(clientQPS)
   148  	klog.Infof("client QPS set to: %v. Burst to: %v", config.QPS, config.Burst)
   149  
   150  	var immutableUserMSIsList []string
   151  	if immutableUserMSIs != "" {
   152  		immutableUserMSIsList = strings.Split(immutableUserMSIs, ",")
   153  	}
   154  
   155  	micConfig := &mic.Config{
   156  		CloudCfgPath:                        cloudconfig,
   157  		RestConfig:                          config,
   158  		IsNamespaced:                        forceNamespaced,
   159  		SyncRetryInterval:                   syncRetryDuration,
   160  		LeaderElectionCfg:                   &leaderElectionCfg,
   161  		CreateDeleteBatch:                   createDeleteBatch,
   162  		ImmutableUserMSIsList:               immutableUserMSIsList,
   163  		CMcfg:                               &cmConfig,
   164  		TypeUpgradeCfg:                      &typeUpgradeConfig,
   165  		UpdateUserMSICfg:                    &updateUserMSIConfig,
   166  		IdentityAssignmentReconcileInterval: identityAssignmentReconcileInterval,
   167  	}
   168  
   169  	micClient, err := mic.NewMICClient(micConfig)
   170  	if err != nil {
   171  		klog.Fatalf("failed to create MIC client, error: %+v", err)
   172  	}
   173  
   174  	// Health probe will always report success once its started.
   175  	// MIC instance will report the contents as "Active" only once its elected the leader
   176  	// and starts the sync loop.
   177  	probes.InitAndStart(httpProbePort, &micClient.SyncLoopStarted)
   178  
   179  	// Register and expose metrics views
   180  	if err = metrics.RegisterAndExport(prometheusPort); err != nil {
   181  		klog.Fatalf("failed to register and export metrics on port %s, error: %+v", prometheusPort, err)
   182  	}
   183  
   184  	// Starts the leader election loop
   185  	micClient.Run()
   186  	klog.Info("aad-pod-identity controller initialized!!")
   187  	select {}
   188  }
   189  
   190  // Create the client config. Use kubeconfig if given, otherwise assume in-cluster.
   191  func buildConfig(kubeconfigPath string) (*rest.Config, error) {
   192  	if kubeconfigPath != "" {
   193  		return clientcmd.BuildConfigFromFlags("", kubeconfigPath)
   194  	}
   195  	return rest.InClusterConfig()
   196  }