mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-08 11:38:15 +00:00
Add iSCSI CHAP authentication
Signed-off-by: Huamin Chen <hchen@redhat.com>
This commit is contained in:
parent
777eb32e91
commit
9298217126
@ -88,6 +88,10 @@ func VisitPodSecretNames(pod *api.Pod, visitor func(string) bool) bool {
|
|||||||
if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
|
if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case source.ISCSI != nil:
|
||||||
|
if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -85,7 +85,11 @@ func TestPodSecrets(t *testing.T) {
|
|||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
ScaleIO: &api.ScaleIOVolumeSource{
|
ScaleIO: &api.ScaleIOVolumeSource{
|
||||||
SecretRef: &api.LocalObjectReference{
|
SecretRef: &api.LocalObjectReference{
|
||||||
Name: "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef"}}}}},
|
Name: "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef"}}}}, {
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
ISCSI: &api.ISCSIVolumeSource{
|
||||||
|
SecretRef: &api.LocalObjectReference{
|
||||||
|
Name: "Spec.Volumes[*].VolumeSource.ISCSI.SecretRef"}}}}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
extractedNames := sets.NewString()
|
extractedNames := sets.NewString()
|
||||||
@ -114,6 +118,7 @@ func TestPodSecrets(t *testing.T) {
|
|||||||
"Spec.Volumes[*].VolumeSource.Secret",
|
"Spec.Volumes[*].VolumeSource.Secret",
|
||||||
"Spec.Volumes[*].VolumeSource.Secret.SecretName",
|
"Spec.Volumes[*].VolumeSource.Secret.SecretName",
|
||||||
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
|
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
|
||||||
|
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
|
||||||
)
|
)
|
||||||
secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&api.Pod{}))
|
secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&api.Pod{}))
|
||||||
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
||||||
|
@ -176,7 +176,10 @@ func VisitPodSecretNames(pod *v1.Pod, visitor func(string) bool) bool {
|
|||||||
if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
|
if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case source.ISCSI != nil:
|
||||||
|
if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -253,7 +253,11 @@ func TestPodSecrets(t *testing.T) {
|
|||||||
VolumeSource: v1.VolumeSource{
|
VolumeSource: v1.VolumeSource{
|
||||||
ScaleIO: &v1.ScaleIOVolumeSource{
|
ScaleIO: &v1.ScaleIOVolumeSource{
|
||||||
SecretRef: &v1.LocalObjectReference{
|
SecretRef: &v1.LocalObjectReference{
|
||||||
Name: "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef"}}}}},
|
Name: "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef"}}}}, {
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ISCSI: &v1.ISCSIVolumeSource{
|
||||||
|
SecretRef: &v1.LocalObjectReference{
|
||||||
|
Name: "Spec.Volumes[*].VolumeSource.ISCSI.SecretRef"}}}}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
extractedNames := sets.NewString()
|
extractedNames := sets.NewString()
|
||||||
@ -282,6 +286,7 @@ func TestPodSecrets(t *testing.T) {
|
|||||||
"Spec.Volumes[*].VolumeSource.Secret",
|
"Spec.Volumes[*].VolumeSource.Secret",
|
||||||
"Spec.Volumes[*].VolumeSource.Secret.SecretName",
|
"Spec.Volumes[*].VolumeSource.Secret.SecretName",
|
||||||
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
|
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
|
||||||
|
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
|
||||||
)
|
)
|
||||||
secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&v1.Pod{}))
|
secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&v1.Pod{}))
|
||||||
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
||||||
|
@ -99,10 +99,23 @@ func (plugin *iscsiPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
|
|||||||
|
|
||||||
func (plugin *iscsiPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
func (plugin *iscsiPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
||||||
// Inject real implementations here, test through the internal function.
|
// Inject real implementations here, test through the internal function.
|
||||||
return plugin.newMounterInternal(spec, pod.UID, &ISCSIUtil{}, plugin.host.GetMounter())
|
var secret map[string]string
|
||||||
|
source, _, err := getVolumeSource(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if source.SecretRef != nil {
|
||||||
|
if secret, err = ioutil.GetSecretForPod(pod, source.SecretRef.Name, plugin.host.GetKubeClient()); err != nil {
|
||||||
|
glog.Errorf("Couldn't get secret from %v/%v", pod.Namespace, source.SecretRef)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugin.newMounterInternal(spec, pod.UID, &ISCSIUtil{}, plugin.host.GetMounter(), secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface) (volume.Mounter, error) {
|
func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, secret map[string]string) (volume.Mounter, error) {
|
||||||
// iscsi volumes used directly in a pod have a ReadOnly flag set by the pod author.
|
// iscsi volumes used directly in a pod have a ReadOnly flag set by the pod author.
|
||||||
// iscsi volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
|
// iscsi volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
|
||||||
iscsi, readOnly, err := getVolumeSource(spec)
|
iscsi, readOnly, err := getVolumeSource(spec)
|
||||||
@ -127,6 +140,9 @@ func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UI
|
|||||||
iqn: iscsi.IQN,
|
iqn: iscsi.IQN,
|
||||||
lun: lun,
|
lun: lun,
|
||||||
iface: iface,
|
iface: iface,
|
||||||
|
chap_discovery: iscsi.DiscoveryCHAPAuth,
|
||||||
|
chap_session: iscsi.SessionCHAPAuth,
|
||||||
|
secret: secret,
|
||||||
manager: manager,
|
manager: manager,
|
||||||
plugin: plugin},
|
plugin: plugin},
|
||||||
fsType: iscsi.FSType,
|
fsType: iscsi.FSType,
|
||||||
@ -179,6 +195,9 @@ type iscsiDisk struct {
|
|||||||
iqn string
|
iqn string
|
||||||
lun string
|
lun string
|
||||||
iface string
|
iface string
|
||||||
|
chap_discovery bool
|
||||||
|
chap_session bool
|
||||||
|
secret map[string]string
|
||||||
plugin *iscsiPlugin
|
plugin *iscsiPlugin
|
||||||
// Utility interface that provides API calls to the provider to attach/detach disks.
|
// Utility interface that provides API calls to the provider to attach/detach disks.
|
||||||
manager diskManager
|
manager diskManager
|
||||||
|
@ -141,7 +141,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
|
|||||||
fakeManager := NewFakeDiskManager()
|
fakeManager := NewFakeDiskManager()
|
||||||
defer fakeManager.Cleanup()
|
defer fakeManager.Cleanup()
|
||||||
fakeMounter := &mount.FakeMounter{}
|
fakeMounter := &mount.FakeMounter{}
|
||||||
mounter, err := plug.(*iscsiPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter)
|
mounter, err := plug.(*iscsiPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to make a new Mounter: %v", err)
|
t.Errorf("Failed to make a new Mounter: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,59 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
chap_st = []string{
|
||||||
|
"discovery.sendtargets.auth.username",
|
||||||
|
"discovery.sendtargets.auth.password",
|
||||||
|
"discovery.sendtargets.auth.username_in",
|
||||||
|
"discovery.sendtargets.auth.password_in"}
|
||||||
|
chap_sess = []string{
|
||||||
|
"node.session.auth.username",
|
||||||
|
"node.session.auth.password",
|
||||||
|
"node.session.auth.username_in",
|
||||||
|
"node.session.auth.password_in"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func updateISCSIDiscoverydb(b iscsiDiskMounter, tp string) error {
|
||||||
|
if b.chap_discovery {
|
||||||
|
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.iface, "-o", "update", "-n", "discovery.sendtargets.auth.authmethod", "-v", "CHAP"})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("iscsi: failed to update discoverydb with CHAP, output: %v", string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range chap_st {
|
||||||
|
v := b.secret[k]
|
||||||
|
if len(v) > 0 {
|
||||||
|
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.iface, "-o", "update", "-n", k, "-v", v})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("iscsi: failed to update discoverydb key %q with value %q error: %v", k, v, string(out))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateISCSINode(b iscsiDiskMounter, tp string) error {
|
||||||
|
if b.chap_session {
|
||||||
|
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", tp, "-T", b.iqn, "-I", b.iface, "-o", "update", "-n", "node.session.auth.authmethod", "-v", "CHAP"})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("iscsi: failed to update node with CHAP, output: %v", string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range chap_sess {
|
||||||
|
v := b.secret[k]
|
||||||
|
if len(v) > 0 {
|
||||||
|
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", tp, "-T", b.iqn, "-I", b.iface, "-o", "update", "-n", k, "-v", v})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("iscsi: failed to update node session key %q with value %q error: %v", k, v, string(out))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// stat a path, if not exists, retry maxRetries times
|
// stat a path, if not exists, retry maxRetries times
|
||||||
// when iscsi transports other than default are used, use glob instead as pci id of device is unknown
|
// when iscsi transports other than default are used, use glob instead as pci id of device is unknown
|
||||||
type StatFunc func(string) (os.FileInfo, error)
|
type StatFunc func(string) (os.FileInfo, error)
|
||||||
@ -105,6 +158,7 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
|
|||||||
var devicePath string
|
var devicePath string
|
||||||
var devicePaths []string
|
var devicePaths []string
|
||||||
var iscsiTransport string
|
var iscsiTransport string
|
||||||
|
var lastErr error
|
||||||
|
|
||||||
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "iface", "-I", b.iface, "-o", "show"})
|
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "iface", "-I", b.iface, "-o", "show"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -133,21 +187,41 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
|
|||||||
}
|
}
|
||||||
exist := waitForPathToExist(devicePath, 1, iscsiTransport)
|
exist := waitForPathToExist(devicePath, 1, iscsiTransport)
|
||||||
if exist == false {
|
if exist == false {
|
||||||
// discover iscsi target
|
// build discoverydb and discover iscsi target
|
||||||
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discovery", "-t", "sendtargets", "-p", tp, "-I", b.iface})
|
b.plugin.execCommand("iscsiadm", []string{"-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.iface, "-o", "new"})
|
||||||
|
// update discoverydb with CHAP secret
|
||||||
|
err = updateISCSIDiscoverydb(b, tp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("iscsi: failed to sendtargets to portal %s error: %s", tp, string(out))
|
lastErr = fmt.Errorf("iscsi: failed to update discoverydb to portal %s error: %v", tp, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.iface, "--discover"})
|
||||||
|
if err != nil {
|
||||||
|
// delete discoverydb record
|
||||||
|
b.plugin.execCommand("iscsiadm", []string{"-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.iface, "-o", "delete"})
|
||||||
|
lastErr = fmt.Errorf("iscsi: failed to sendtargets to portal %s output: %s, err %v", tp, string(out), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = updateISCSINode(b, tp)
|
||||||
|
if err != nil {
|
||||||
|
// failure to update node db is rare. But deleting record will likely impact those who already start using it.
|
||||||
|
lastErr = fmt.Errorf("iscsi: failed to update iscsi node to portal %s error: %v", tp, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// login to iscsi target
|
// login to iscsi target
|
||||||
out, err = b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", tp, "-T", b.iqn, "-I", b.iface, "--login"})
|
out, err = b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", tp, "-T", b.iqn, "-I", b.iface, "--login"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("iscsi: failed to attach disk:Error: %s (%v)", string(out), err)
|
// delete the node record from database
|
||||||
|
b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", tp, "-I", b.iface, "-T", b.iqn, "-o", "delete"})
|
||||||
|
lastErr = fmt.Errorf("iscsi: failed to attach disk: Error: %s (%v)", string(out), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
exist = waitForPathToExist(devicePath, 10, iscsiTransport)
|
exist = waitForPathToExist(devicePath, 10, iscsiTransport)
|
||||||
if !exist {
|
if !exist {
|
||||||
glog.Errorf("Could not attach disk: Timeout after 10s")
|
glog.Errorf("Could not attach disk: Timeout after 10s")
|
||||||
|
// update last error
|
||||||
|
lastErr = fmt.Errorf("Could not attach disk: Timeout after 10s")
|
||||||
|
continue
|
||||||
} else {
|
} else {
|
||||||
devicePaths = append(devicePaths, devicePath)
|
devicePaths = append(devicePaths, devicePath)
|
||||||
}
|
}
|
||||||
@ -158,8 +232,8 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(devicePaths) == 0 {
|
if len(devicePaths) == 0 {
|
||||||
glog.Errorf("iscsi: failed to get any path for iscsi disk")
|
glog.Errorf("iscsi: failed to get any path for iscsi disk, last err seen:\n%v", lastErr)
|
||||||
return errors.New("failed to get any path for iscsi disk")
|
return fmt.Errorf("failed to get any path for iscsi disk, last err seen:\n%v", lastErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Make sure we use a valid devicepath to find mpio device.
|
//Make sure we use a valid devicepath to find mpio device.
|
||||||
@ -233,12 +307,24 @@ func (util *ISCSIUtil) DetachDisk(c iscsiDiskUnmounter, mntPath string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("iscsi: failed to detach disk Error: %s", string(out))
|
glog.Errorf("iscsi: failed to detach disk Error: %s", string(out))
|
||||||
}
|
}
|
||||||
|
// Delete the node record
|
||||||
|
glog.Infof("iscsi: delete node record target %s iqn %s", portal, iqn)
|
||||||
|
out, err = c.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", portal, "-T", iqn, "-I", iface, "-o", "delete"})
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("iscsi: failed to delete node record Error: %s", string(out))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
glog.Infof("iscsi: log out target %s iqn %s", portal, iqn)
|
glog.Infof("iscsi: log out target %s iqn %s", portal, iqn)
|
||||||
out, err := c.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"})
|
out, err := c.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("iscsi: failed to detach disk Error: %s", string(out))
|
glog.Errorf("iscsi: failed to detach disk Error: %s", string(out))
|
||||||
}
|
}
|
||||||
|
// Delete the node record
|
||||||
|
glog.Infof("iscsi: delete node record target %s iqn %s", portal, iqn)
|
||||||
|
out, err = c.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", portal, "-T", iqn, "-o", "delete"})
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("iscsi: failed to delete node record Error: %s", string(out))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user