Skip to content

Commit

Permalink
Merge pull request #709 from andyzhangx/customize-kerberos-settings
Browse files Browse the repository at this point in the history
feat: customize kerberos settings
  • Loading branch information
andyzhangx committed Dec 15, 2023
2 parents 5275b2a + 2540e18 commit 4a84e51
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 19 deletions.
2 changes: 2 additions & 0 deletions charts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ The following table lists the configurable parameters of the latest SMB CSI Driv
| `linux.dsName` | name of driver daemonset on linux | `csi-smb-node` |
| `linux.dnsPolicy` | dnsPolicy of driver node daemonset, available values: `Default`, `ClusterFirstWithHostNet`, `ClusterFirst` | `ClusterFirstWithHostNet` |
| `linux.kubelet` | configure kubelet directory path on Linux agent node node | `/var/lib/kubelet` |
| `linux.krb5CacheDirectory` | directory for kerberos cache on Linux agent node node | `/var/lib/kubelet/kerberos/` |
| `linux.krb5Prefix` | prefix for kerberos cache on Linux agent node node | `krb5cc_` |
| `linux.resources.livenessProbe.limits.memory` | liveness-probe memory limits | `100Mi` |
| `linux.resources.livenessProbe.requests.cpu` | liveness-probe cpu requests limits | `10m` |
| `linux.resources.livenessProbe.requests.memory` | liveness-probe memory requests limits | `20Mi` |
Expand Down
Binary file modified charts/latest/csi-driver-smb-v0.0.0.tgz
Binary file not shown.
2 changes: 2 additions & 0 deletions charts/latest/csi-driver-smb/templates/csi-smb-node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ spec:
- "--endpoint=$(CSI_ENDPOINT)"
- "--nodeid=$(KUBE_NODE_NAME)"
- "--enable-get-volume-stats={{ .Values.feature.enableGetVolumeStats }}"
- "--krb5-cache-directory={{ .Values.linux.krb5CacheDirectory }}"
- "--krb5-prefix={{ .Values.linux.krb5Prefix }}"
ports:
- containerPort: {{ .Values.node.livenessProbe.healthPort }}
name: healthz
Expand Down
2 changes: 2 additions & 0 deletions charts/latest/csi-driver-smb/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ linux:
dsName: csi-smb-node # daemonset name
dnsPolicy: ClusterFirstWithHostNet # available values: Default, ClusterFirstWithHostNet, ClusterFirst
kubelet: /var/lib/kubelet
krb5CacheDirectory: /var/lib/kubelet/kerberos/ # directory for kerberos credential cache
krb5Prefix: "krb5cc_" # prefix for kerberos credential cache
tolerations:
- operator: "Exists"
resources:
Expand Down
4 changes: 4 additions & 0 deletions cmd/smbplugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ var (
removeSMBMappingDuringUnmount = flag.Bool("remove-smb-mapping-during-unmount", true, "remove SMBMapping during unmount on Windows node")
workingMountDir = flag.String("working-mount-dir", "/tmp", "working directory for provisioner to mount smb shares temporarily")
volStatsCacheExpireInMinutes = flag.Int("vol-stats-cache-expire-in-minutes", 10, "The cache expire time in minutes for volume stats cache")
krb5CacheDirectory = flag.String("krb5-cache-directory", "/var/lib/kubelet/kerberos/", "The directory for kerberos cache")
krb5Prefix = flag.String("krb5-prefix", "krb5cc_", "The prefix for kerberos cache")
)

func main() {
Expand Down Expand Up @@ -74,6 +76,8 @@ func handle() {
RemoveSMBMappingDuringUnmount: *removeSMBMappingDuringUnmount,
WorkingMountDir: *workingMountDir,
VolStatsCacheExpireInMinutes: *volStatsCacheExpireInMinutes,
Krb5CacheDirectory: *krb5CacheDirectory,
Krb5Prefix: *krb5Prefix,
}
driver := smb.NewDriver(&driverOptions)
driver.Run(*endpoint, *kubeconfig, false)
Expand Down
32 changes: 16 additions & 16 deletions pkg/smb/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func (d *Driver) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequ
sensitiveMountOptions = []string{password}
}
} else {
var useKerberosCache, err = ensureKerberosCache(volumeID, mountFlags, secrets)
var useKerberosCache, err = ensureKerberosCache(d.krb5CacheDirectory, d.krb5Prefix, volumeID, mountFlags, secrets)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("Error writing kerberos cache: %v", err))
}
Expand Down Expand Up @@ -264,7 +264,7 @@ func (d *Driver) NodeUnstageVolume(_ context.Context, req *csi.NodeUnstageVolume
return nil, status.Errorf(codes.Internal, "failed to unmount staging target %q: %v", stagingTargetPath, err)
}

if err := deleteKerberosCache(volumeID); err != nil {
if err := deleteKerberosCache(d.krb5CacheDirectory, volumeID); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete kerberos cache: %v", err)
}

Expand Down Expand Up @@ -469,12 +469,12 @@ func getCredUID(mountFlags []string) (int, error) {
return -1, fmt.Errorf("Can't find credUid in mount flags")
}

func getKrb5CcacheName(credUID int) string {
func getKrb5CcacheName(krb5Prefix string, credUID int) string {
return fmt.Sprintf("%s%d", krb5Prefix, credUID)
}

// returns absolute path for name of file inside krb5CacheDirectory
func getKerberosFilePath(fileName string) string {
func getKerberosFilePath(krb5CacheDirectory, fileName string) string {
return fmt.Sprintf("%s%s", krb5CacheDirectory, fileName)
}

Expand All @@ -483,7 +483,7 @@ func volumeKerberosCacheName(volumeID string) string {
return strings.ReplaceAll(strings.ReplaceAll(encoded, "/", "-"), "+", "_")
}

func kerberosCacheDirectoryExists() (bool, error) {
func kerberosCacheDirectoryExists(krb5CacheDirectory string) (bool, error) {
_, err := os.Stat(krb5CacheDirectory)
if os.IsNotExist(err) {
return false, status.Error(codes.Internal, fmt.Sprintf("Directory for kerberos caches must exist, it will not be created: %s: %v", krb5CacheDirectory, err))
Expand All @@ -493,8 +493,8 @@ func kerberosCacheDirectoryExists() (bool, error) {
return true, nil
}

func getKerberosCache(credUID int, secrets map[string]string) (string, []byte, error) {
var krb5CcacheName = getKrb5CcacheName(credUID)
func getKerberosCache(krb5CacheDirectory, krb5Prefix string, credUID int, secrets map[string]string) (string, []byte, error) {
var krb5CcacheName = getKrb5CcacheName(krb5Prefix, credUID)
var krb5CcacheContent string
for k, v := range secrets {
switch strings.ToLower(k) {
Expand All @@ -509,33 +509,33 @@ func getKerberosCache(credUID int, secrets map[string]string) (string, []byte, e
if err != nil {
return "", nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Malformed kerberos cache in key %s, expected to be in base64 form: %v", krb5CcacheName, err))
}
var krb5CacheFileName = getKerberosFilePath(getKrb5CcacheName(credUID))
var krb5CacheFileName = getKerberosFilePath(krb5CacheDirectory, getKrb5CcacheName(krb5Prefix, credUID))

return krb5CacheFileName, content, nil
}

// Create kerberos cache in the file based on the VolumeID, so it can be cleaned up during unstage
// At the same time, kerberos expects to find cache in file named "krb5cc_*", so creating symlink
// will allow both clean up and serving proper cache to the kerberos.
func ensureKerberosCache(volumeID string, mountFlags []string, secrets map[string]string) (bool, error) {
func ensureKerberosCache(krb5CacheDirectory, krb5Prefix, volumeID string, mountFlags []string, secrets map[string]string) (bool, error) {
var securityIsKerberos = hasKerberosMountOption(mountFlags)
if securityIsKerberos {
_, err := kerberosCacheDirectoryExists()
_, err := kerberosCacheDirectoryExists(krb5CacheDirectory)
if err != nil {
return false, err
}
credUID, err := getCredUID(mountFlags)
if err != nil {
return false, err
}
krb5CacheFileName, content, err := getKerberosCache(credUID, secrets)
krb5CacheFileName, content, err := getKerberosCache(krb5CacheDirectory, krb5Prefix, credUID, secrets)
if err != nil {
return false, err
}
// Write cache into volumeId-based filename, so it can be cleaned up later
volumeIDCacheFileName := volumeKerberosCacheName(volumeID)

volumeIDCacheAbsolutePath := getKerberosFilePath(volumeIDCacheFileName)
volumeIDCacheAbsolutePath := getKerberosFilePath(krb5CacheDirectory, volumeIDCacheFileName)
if err := os.WriteFile(volumeIDCacheAbsolutePath, content, os.FileMode(0700)); err != nil {
return false, status.Error(codes.Internal, fmt.Sprintf("Couldn't write kerberos cache to file %s: %v", volumeIDCacheAbsolutePath, err))
}
Expand All @@ -561,8 +561,8 @@ func ensureKerberosCache(volumeID string, mountFlags []string, secrets map[strin
return false, nil
}

func deleteKerberosCache(volumeID string) error {
exists, err := kerberosCacheDirectoryExists()
func deleteKerberosCache(krb5CacheDirectory, volumeID string) error {
exists, err := kerberosCacheDirectoryExists(krb5CacheDirectory)
// If not supported, simply return
if !exists {
return nil
Expand All @@ -573,7 +573,7 @@ func deleteKerberosCache(volumeID string) error {

volumeIDCacheFileName := volumeKerberosCacheName(volumeID)

var volumeIDCacheAbsolutePath = getKerberosFilePath(volumeIDCacheFileName)
var volumeIDCacheAbsolutePath = getKerberosFilePath(krb5CacheDirectory, volumeIDCacheFileName)
_, err = os.Stat(volumeIDCacheAbsolutePath)
// Not created or already removed
if os.IsNotExist(err) {
Expand All @@ -585,7 +585,7 @@ func deleteKerberosCache(volumeID string) error {
// If file with cache exists, full clean means removing symlinks to the file.
dirEntries, _ := os.ReadDir(krb5CacheDirectory)
for _, dirEntry := range dirEntries {
filePath := getKerberosFilePath(dirEntry.Name())
filePath := getKerberosFilePath(krb5CacheDirectory, dirEntry.Name())
lStat, _ := os.Lstat(filePath)
// If it's a symlink, checking if it's pointing to the volume file in question
if lStat != nil {
Expand Down
4 changes: 3 additions & 1 deletion pkg/smb/nodeserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,8 @@ func TestGetKerberosCache(t *testing.T) {
ticket := []byte{'G', 'O', 'L', 'A', 'N', 'G'}
base64Ticket := base64.StdEncoding.EncodeToString(ticket)
credUID := 1000
krb5CacheDirectory := "/var/lib/kubelet/kerberos/"
krb5Prefix := "krb5cc_"
goodFileName := fmt.Sprintf("%s%s%d", krb5CacheDirectory, krb5Prefix, credUID)
krb5CcacheName := "krb5cc_1000"

Expand Down Expand Up @@ -855,7 +857,7 @@ func TestGetKerberosCache(t *testing.T) {
}

for _, test := range tests {
fileName, content, err := getKerberosCache(test.credUID, test.secrets)
fileName, content, err := getKerberosCache(krb5CacheDirectory, krb5Prefix, test.credUID, test.secrets)
if !reflect.DeepEqual(err, test.expectedErr) {
t.Errorf("[%s]: Expected error : %v, Actual error: %v", test.desc, test.expectedErr, err)
} else {
Expand Down
8 changes: 6 additions & 2 deletions pkg/smb/smb.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ const (
sourceField = "source"
subDirField = "subdir"
domainField = "domain"
krb5Prefix = "krb5cc_"
krb5CacheDirectory = "/var/lib/kubelet/kerberos/"
mountOptionsField = "mountoptions"
defaultDomainName = "AZURE"
pvcNameKey = "csi.storage.k8s.io/pvc/name"
Expand All @@ -59,6 +57,8 @@ type DriverOptions struct {
RemoveSMBMappingDuringUnmount bool
WorkingMountDir string
VolStatsCacheExpireInMinutes int
Krb5CacheDirectory string
Krb5Prefix string
}

// Driver implements all interfaces of CSI drivers
Expand All @@ -74,6 +74,8 @@ type Driver struct {
volStatsCache azcache.Resource
// this only applies to Windows node
removeSMBMappingDuringUnmount bool
krb5CacheDirectory string
krb5Prefix string
}

// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
Expand All @@ -86,6 +88,8 @@ func NewDriver(options *DriverOptions) *Driver {
driver.enableGetVolumeStats = options.EnableGetVolumeStats
driver.removeSMBMappingDuringUnmount = options.RemoveSMBMappingDuringUnmount
driver.workingMountDir = options.WorkingMountDir
driver.krb5CacheDirectory = options.Krb5CacheDirectory
driver.krb5Prefix = options.Krb5Prefix
driver.volumeLocks = newVolumeLocks()

if options.VolStatsCacheExpireInMinutes <= 0 {
Expand Down

0 comments on commit 4a84e51

Please sign in to comment.