@@ -17,12 +17,22 @@ limitations under the License.
1717package smb
1818
1919import (
20+ "context"
21+ "errors"
2022 "fmt"
23+ "net"
24+ "os"
25+ "path/filepath"
2126 "strings"
2227 "time"
2328
2429 "github.com/container-storage-interface/spec/lib/go/csi"
2530
31+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+ "k8s.io/client-go/kubernetes"
33+ "k8s.io/client-go/rest"
34+ "k8s.io/client-go/tools/clientcmd"
35+ certutil "k8s.io/client-go/util/cert"
2636 "k8s.io/klog/v2"
2737 mount "k8s.io/mount-utils"
2838
@@ -40,8 +50,12 @@ const (
4050 subDirField = "subdir"
4151 domainField = "domain"
4252 mountOptionsField = "mountoptions"
53+ secretNameField = "secretname"
54+ secretNamespaceField = "secretnamespace"
4355 paramOnDelete = "ondelete"
4456 defaultDomainName = "AZURE"
57+ ephemeralField = "csi.storage.k8s.io/ephemeral"
58+ podNamespaceField = "csi.storage.k8s.io/pod.namespace"
4559 pvcNameKey = "csi.storage.k8s.io/pvc/name"
4660 pvcNamespaceKey = "csi.storage.k8s.io/pvc/namespace"
4761 pvNameKey = "csi.storage.k8s.io/pv/name"
@@ -56,6 +70,7 @@ const (
5670 dirMode = "dir_mode"
5771 defaultFileMode = "0777"
5872 defaultDirMode = "0777"
73+ trueValue = "true"
5974)
6075
6176var supportedOnDeleteValues = []string {"" , "delete" , retain , archive }
@@ -74,6 +89,7 @@ type DriverOptions struct {
7489 DefaultOnDeletePolicy string
7590 RemoveArchivedVolumePath bool
7691 EnableWindowsHostProcess bool
92+ Kubeconfig string
7793}
7894
7995// Driver implements all interfaces of CSI drivers
@@ -102,6 +118,8 @@ type Driver struct {
102118 defaultOnDeletePolicy string
103119 removeArchivedVolumePath bool
104120 enableWindowsHostProcess bool
121+ kubeconfig string
122+ kubeClient kubernetes.Interface
105123}
106124
107125// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
@@ -116,6 +134,7 @@ func NewDriver(options *DriverOptions) *Driver {
116134 driver .removeArchivedVolumePath = options .RemoveArchivedVolumePath
117135 driver .workingMountDir = options .WorkingMountDir
118136 driver .enableWindowsHostProcess = options .EnableWindowsHostProcess
137+ driver .kubeconfig = options .Kubeconfig
119138 driver .volumeLocks = newVolumeLocks ()
120139
121140 driver .krb5CacheDirectory = options .Krb5CacheDirectory
@@ -138,6 +157,15 @@ func NewDriver(options *DriverOptions) *Driver {
138157 if driver .volDeletionCache , err = azcache .NewTimedCache (time .Minute , getter , false ); err != nil {
139158 klog .Fatalf ("%v" , err )
140159 }
160+
161+ kubeCfg , err := getKubeConfig (driver .kubeconfig , driver .enableWindowsHostProcess )
162+ if err == nil && kubeCfg != nil {
163+ if driver .kubeClient , err = kubernetes .NewForConfig (kubeCfg ); err != nil {
164+ klog .Warningf ("NewForConfig failed with error: %v" , err )
165+ }
166+ } else {
167+ klog .Warningf ("get kubeconfig(%s) failed with error: %v" , driver .kubeconfig , err )
168+ }
141169 return & driver
142170}
143171
@@ -189,6 +217,24 @@ func (d *Driver) Run(endpoint, _ string, testMode bool) {
189217 s .Wait ()
190218}
191219
220+ // GetUserNamePasswordFromSecret get storage account key from k8s secret
221+ // return <username, password, domain, error>
222+ func (d * Driver ) GetUserNamePasswordFromSecret (ctx context.Context , secretName , secretNamespace string ) (string , string , string , error ) {
223+ if d .kubeClient == nil {
224+ return "" , "" , "" , fmt .Errorf ("could not username and password from secret(%s): KubeClient is nil" , secretName )
225+ }
226+
227+ secret , err := d .kubeClient .CoreV1 ().Secrets (secretNamespace ).Get (ctx , secretName , metav1.GetOptions {})
228+ if err != nil {
229+ return "" , "" , "" , fmt .Errorf ("could not get secret(%v): %v" , secretName , err )
230+ }
231+
232+ username := strings .TrimSpace (string (secret .Data [usernameField ][:]))
233+ password := strings .TrimSpace (string (secret .Data [passwordField ][:]))
234+ domain := strings .TrimSpace (string (secret .Data [domainField ][:]))
235+ return username , password , domain , nil
236+ }
237+
192238func IsCorruptedDir (dir string ) bool {
193239 _ , pathErr := mount .PathExists (dir )
194240 return pathErr != nil && mount .IsCorruptedMnt (pathErr )
@@ -279,3 +325,61 @@ func getRootDir(path string) string {
279325 parts := strings .Split (path , "/" )
280326 return parts [0 ]
281327}
328+
329+ func getKubeConfig (kubeconfig string , enableWindowsHostProcess bool ) (config * rest.Config , err error ) {
330+ if kubeconfig != "" {
331+ if config , err = clientcmd .BuildConfigFromFlags ("" , kubeconfig ); err != nil {
332+ return nil , err
333+ }
334+ } else {
335+ if config , err = inClusterConfig (enableWindowsHostProcess ); err != nil {
336+ return nil , err
337+ }
338+ }
339+ return config , err
340+ }
341+
342+ // inClusterConfig is copied from https://github.com/kubernetes/client-go/blob/b46677097d03b964eab2d67ffbb022403996f4d4/rest/config.go#L507-L541
343+ // When using Windows HostProcess containers, the path "/var/run/secrets/kubernetes.io/serviceaccount/" is under host, not container.
344+ // Then the token and ca.crt files would be not found.
345+ // An environment variable $CONTAINER_SANDBOX_MOUNT_POINT is set upon container creation and provides the absolute host path to the container volume.
346+ // See https://kubernetes.io/docs/tasks/configure-pod-container/create-hostprocess-pod/#volume-mounts for more details.
347+ func inClusterConfig (enableWindowsHostProcess bool ) (* rest.Config , error ) {
348+ var (
349+ tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
350+ rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
351+ )
352+ if enableWindowsHostProcess {
353+ containerSandboxMountPath := os .Getenv ("CONTAINER_SANDBOX_MOUNT_POINT" )
354+ if len (containerSandboxMountPath ) == 0 {
355+ return nil , errors .New ("unable to load in-cluster configuration, containerSandboxMountPath must be defined" )
356+ }
357+ tokenFile = filepath .Join (containerSandboxMountPath , tokenFile )
358+ rootCAFile = filepath .Join (containerSandboxMountPath , rootCAFile )
359+ }
360+
361+ host , port := os .Getenv ("KUBERNETES_SERVICE_HOST" ), os .Getenv ("KUBERNETES_SERVICE_PORT" )
362+ if len (host ) == 0 || len (port ) == 0 {
363+ return nil , rest .ErrNotInCluster
364+ }
365+
366+ token , err := os .ReadFile (tokenFile )
367+ if err != nil {
368+ return nil , err
369+ }
370+
371+ tlsClientConfig := rest.TLSClientConfig {}
372+
373+ if _ , err := certutil .NewPool (rootCAFile ); err != nil {
374+ klog .Errorf ("Expected to load root CA config from %s, but got err: %v" , rootCAFile , err )
375+ } else {
376+ tlsClientConfig .CAFile = rootCAFile
377+ }
378+
379+ return & rest.Config {
380+ Host : "https://" + net .JoinHostPort (host , port ),
381+ TLSClientConfig : tlsClientConfig ,
382+ BearerToken : string (token ),
383+ BearerTokenFile : tokenFile ,
384+ }, nil
385+ }
0 commit comments