pam_container -- jeszcze lżejsza wirtualizacja

1,905 views

Published on

LXC + python + PAM = ♥

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,905
On SlideShare
0
From Embeds
0
Number of Embeds
750
Actions
Shares
0
Downloads
11
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

pam_container -- jeszcze lżejsza wirtualizacja

  1. 1. pam_container.py jeszcze lżejsza wirtualizacja Grzegorz Nosek, MegiTeam
  2. 2. pyton* w przezroczystym kontenerze *wąż zbożowy to prawie jak pyton :)
  3. 3. wirtualizacja sprzętu KVM, Xen, ... http://www.flickr.com/photos/belviso/5691301348
  4. 4. wirtualizacja OS LXC, OpenVZ, ... http://www.flickr.com/photos/belviso/5691301348
  5. 5. wirtualizacja per user pam_container, ...? http://www.flickr.com/photos/belviso/5691301348
  6. 6. wirtualizacja: CPU, pamięć, sieć, FS, ... LXC
  7. 7. wirtualizacja: CPU, pamięć, sieć, FS, ... per użytkownik: cron, ssh, ...LXC + PAM
  8. 8. LXC – namespace'y ipcns mntns netns pidns userns utsns http://www.flickr.com/photos/mbostock/4365347285
  9. 9. LXC – namespace'y ipcns mntns netns pidns userns utsns http://www.flickr.com/photos/mbostock/4365347285
  10. 10. LXC – namespace'y clone() unshare()
  11. 11. LXC – namespace'y /proc/<pid>/ns/* clone() unshare()
  12. 12. LXC – namespace'y /proc/<pid>/ns/* clone() unshare() setns()
  13. 13. LXC – namespace'y /proc/<pid>/ns/* clone() unshare() setns() mount --bind
  14. 14. LXC – namespace'y /proc/<pid>/ns/* clone() unshare() setns() mount --bind namespace: - ma nazwę - żyje nawet bez procesów
  15. 15. PAM session auth password account http://www.flickr.com/photos/brankomaster/3667243737
  16. 16. PAM # grep -v ^# /etc/pam.d/common-auth auth [success=1 default=ignore] pam_unix.so nullok_secure auth requisite pam_deny.so auth required pam_permit.so auth optional pam_cap.so
  17. 17. PAM # grep -v ^# /etc/pam.d/common-auth auth required pam_python.so /lib/security/gandalf.py auth [success=1 default=ignore] pam_unix.so nullok_secure auth requisite pam_deny.so auth required pam_permit.so auth optional pam_cap.so
  18. 18. PAM # cat /lib/security/gandalf.py def pam_sm_authenticate(pamh, flags, args): # you shall not pass return pamh.PAM_AUTH_ERR # wc -l pam_deny.c 89
  19. 19. PAM session + python + namespaces = ♥ pam_container.py
  20. 20. wywołania systemowe? brak biblioteki pythonowej dla setns(), mount() itp.
  21. 21. ctypes from ctypes import CDLL libc = CDLL('libc.so.6') # linux/fs.h MS_RDONLY = 1 # ... MS_MGC_VAL = 0xC0ED0000 def bind_mount(source, target, rec=False): flags = MS_BIND|MS_MGC_VAL if rec: flags |= MS_REC if libc.mount(source, target, 'none', flags, None) < 0: raise OSError('Failed to bind mount {0} at {1}'.format(source, target))
  22. 22. ctypes from ctypes import CDLL libc = CDLL('libc.so.6') # linux/fs.h MS_RDONLY = 1 # ... MS_MGC_VAL = 0xC0ED0000 def bind_mount(source, target, rec=False): flags = MS_BIND|MS_MGC_VAL if rec: flags |= MS_REC if libc.mount(source, target, 'none', flags, None) < 0: raise OSError('Failed to bind mount {0} at {1}'.format(source, target))
  23. 23. wydajność?
  24. 24. przeraża mnie system, w którym istotna jest wydajność logowania – Radomir Dopieralski, PyCon.PL 2012 „
  25. 25. pam_container.py def setup_core_namespaces(user): if not setns(ns_path('ipc', user)): unshare(CLONE_NEWIPC) pin_ns('ipc', user) if not setns(ns_path('uts', user)): unshare(CLONE_NEWUTS) sethostname(user) pin_ns('uts', user)
  26. 26. pam_container.py /var/run/ipcns/user os.open()+libc.setns() mount --bind /proc/self/ns/uts /var/run/utsns/user def setup_core_namespaces(user): if not setns(ns_path('ipc', user)): unshare(CLONE_NEWIPC) pin_ns('ipc', user) if not setns(ns_path('uts', user)): unshare(CLONE_NEWUTS) sethostname(user) pin_ns('uts', user)
  27. 27. pam_container.py netns▸ eth0 vethX2 vethX1 br0 host netns user1 netns eth0 user2 netns eth0
  28. 28. def setup_net_namespace(user): if setns(ns_path('net', user)): return veth_id = random_id() veth_master = 'veth' + veth_id veth_slave = 'veths' + veth_id # ip netns add user # ip link add name veth_master type veth # peer name veth_slave # ip link set veth_slave netns user # ip link set veth_master up # brctl addif br0 veth_master pam_container.py netns▸
  29. 29. def setup_net_namespace(user): if setns(ns_path('net', user)): return veth_id = random_id() veth_master = 'veth' + veth_id veth_slave = 'veths' + veth_id # ip netns add user # ip link add name veth_master type veth # peer name veth_slave # ip link set veth_slave netns user # ip link set veth_master up # brctl addif br0 veth_master/var/run/netns/user pam_container.py netns▸
  30. 30. if not setns(ns_path('net', user)): raise RuntimeError('Failed to setns into a freshly created netns') # ip link set veth_slave name eth0 # ip link set lo up # ip link set eth0 up # ip addr add dev eth0 ... # ip route add default via ... pam_container.py netns▸
  31. 31. if not setns(ns_path('net', user)): raise RuntimeError('Failed to setns into a freshly created netns') # ip link set veth_slave name eth0 # ip link set lo up # ip link set eth0 up # ip addr add dev eth0 ... # ip route add default via ... DHCP: - po FS namespace - proces cały czas w tle :( pam_container.py netns▸
  32. 32. /home user1 .bashrc user2 .zshrc ... pam_container.py mntns▸
  33. 33. /home user1 .bashrc user2 ... /ns user1/home user1 user2/home user2 ... pam_container.py mntns▸
  34. 34. /home user1 .bashrc user2 ... mount --rbind /ns user1/home user1 user2/home user2 ... pam_container.py mntns▸
  35. 35. /home user1 .bashrc user2 ... /ns user1/home user1 .bashrc ... mount --move pam_container.py mntns▸
  36. 36. /home user1 .bashrc /ns mount –-bind /var/empty /ns pam_container.py mntns▸
  37. 37. def pivot_home_dir(user): home_parent = '/ns/{0}/home'.format(user) home = '/ns/{0}/home/{0}'.format(user) bind_mount('/home/{0}'.format(user), home, rec=True) bind_mount(home_parent, home_parent, rec=True) mount(home_parent, '/home', 'none', MS_MOVE, None) pam_container.py mntns▸
  38. 38. :( brak /proc/self/ns/mnt mount = restart (poprawione w 3.8) :) własne /usr/local ln -s fakeroot sudo :) nss_extrausers /var/lib/extrausers/passwd :) mount / -o remount,ro uwaga na /home :) mount /proc -o hidepid=2 w globalnym mntns pam_container.py mntns▸
  39. 39. /sys/fs/cgroups/cpu/lxc/virt/user1/cron/task1 pam_container.py cgroups▸
  40. 40. /sys/fs/cgroups/cpu/lxc/virt/user1/cron/task1 cpu blkio memory ... LXC+pam_container=♥ pam_container.py cgroups▸
  41. 41. # cat /proc/self/cgroup 8:perf_event:/lxc/ovhback 7:blkio:/lxc/ovhback 6:freezer:/lxc/ovhback 5:devices:/lxc/ovhback 4:memory:/lxc/ovhback 3:cpuacct:/lxc/ovhback 2:cpu:/lxc/ovhback 1:cpuset:/lxc/ovhback pam_container.py cgroups▸
  42. 42. CGROUP_ROOT='/sys/fs/cgroup' def setup_cgroups(subgroup): for line in open('/proc/self/cgroup'): idx, subsys, path = line.strip().split(':') cgroup_path = os.path.join(CGROUP_ROOT, subsys, path[1:], subgroup) mkdirs(cgroup_path) # ... with open(os.path.join(cgroup_path, 'tasks'), 'w') as tasks: print >>tasks, os.getpid() pam_container.py cgroups▸
  43. 43. CGROUP_ROOT='/sys/fs/cgroup' def setup_cgroups(subgroup): for line in open('/proc/self/cgroup'): idx, subsys, path = line.strip().split(':') cgroup_path = os.path.join(CGROUP_ROOT, subsys, path[1:], subgroup) mkdirs(cgroup_path) # ... with open(os.path.join(cgroup_path, 'tasks'), 'w') as tasks: print >>tasks, os.getpid() pam_container.py cgroups▸
  44. 44. QA http://www.flickr.com/photos/86979666@N00/7623744452

×