pam_container -- jeszcze lżejsza wirtualizacja

44
pam_container.py jeszcze lżejsza wirtualizacja Grzegorz Nosek, MegiTeam

Transcript of pam_container -- jeszcze lżejsza wirtualizacja

pam_container.pyjeszcze lżejsza wirtualizacja

Grzegorz Nosek, MegiTeam

pyton*

w przezroczysty

m

kontenerze

*wąż zbożowy toprawie jak pyton :)

wirtualizacja sprzętuKVM, Xen, ...

http://www.flickr.com/photos/belviso/5691301348

wirtualizacja OSLXC, OpenVZ, ...

http://www.flickr.com/photos/belviso/5691301348

wirtualizacja per userpam_container, ...?

http://www.flickr.com/photos/belviso/5691301348

wirtualizacja:

CPU, pamięć,

sieć, FS, ...

LXC

wirtualizacja:

CPU, pamięć,

sieć, FS, ...

per użytkownik:cron, ssh, ...LXC + PAM

LXC – namespace'y

ipcns

mntns

netns

pidns

userns

utsns

http

://w

ww

.flic

kr.c

om/ p

hoto

s/m

bost

ock/

4365

3472

85

LXC – namespace'y

ipcns

mntns

netns

pidns

userns

utsns

http

://w

ww

.flic

kr.c

om/ p

hoto

s/m

bost

ock/

4365

3472

85

LXC – namespace'y

clone() unshare()

LXC – namespace'y

/proc/<pid>/ns/*

clone() unshare()

LXC – namespace'y

/proc/<pid>/ns/*

clone() unshare()

setns()

LXC – namespace'y

/proc/<pid>/ns/*

clone() unshare()

setns()

mount --bind

LXC – namespace'y

/proc/<pid>/ns/*

clone() unshare()

setns()

mount --bindnamespace

:

- ma nazwę

- ży je nawet bez

procesów

PAM

session

auth

password

account

http://www.flickr.com/photos/brankomaster/3667243737

PAM

# grep -v ^# /etc/pam.d/common-auth

auth [success=1 default=ignore] \ pam_unix.so nullok_secureauth requisite pam_deny.soauth required pam_permit.soauth optional pam_cap.so

PAM

# grep -v ^# /etc/pam.d/common-auth

auth required pam_python.so \ /lib/security/gandalf.pyauth [success=1 default=ignore] \ pam_unix.so nullok_secureauth requisite pam_deny.soauth required pam_permit.soauth optional pam_cap.so

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.c89

PAM session + python + namespaces = ♥

pam_container.py

wywołania systemowe?brak biblioteki pythonowej dla setns(), mount() itp.

ctypes

from ctypes import CDLL

libc = CDLL('libc.so.6')

# linux/fs.hMS_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))

ctypes

from ctypes import CDLL

libc = CDLL('libc.so.6')

# linux/fs.hMS_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))

wydajność?

przeraża mnie system, w którym

istotna jest wydajność logowania

– Radomir Dopieralski, PyCon.PL 2012

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)

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)

pam_container.py netns▸

eth0

vethX2

vethX1

br0

host netns

user1 netns

eth0

user2 netns

eth0

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▸

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▸

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▸

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 nam

espace

- proces cały czas w t le

:(

pam_container.py netns▸

/home

user1 .bashrcuser2 .zshrc...

pam_container.py mntns▸

/home

user1 .bashrcuser2...

/ns

user1/home user1user2/home user2...

pam_container.py mntns▸

/home

user1 .bashrcuser2...

mount --rbind

/ns

user1/home user1user2/home user2...

pam_container.py mntns▸

/home

user1 .bashrcuser2...

/ns

user1/home user1 .bashrc...

mount --m

ove

pam_container.py mntns▸

/home

user1 .bashrc

/ns

mount –-bind /var/empty /ns

pam_container.py mntns▸

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▸

:( 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▸

/sys/fs/cgroups/cpu/lxc/virt/user1/cron/task1

pam_container.py cgroups▸

/sys/fs/cgroups/cpu/lxc/virt/user1/cron/task1

cpublkiomemory...

LXC+pam_container=♥

pam_container.py cgroups▸

# cat /proc/self/cgroup8:perf_event:/lxc/ovhback7:blkio:/lxc/ovhback6:freezer:/lxc/ovhback5:devices:/lxc/ovhback4:memory:/lxc/ovhback3:cpuacct:/lxc/ovhback2:cpu:/lxc/ovhback1:cpuset:/lxc/ovhback

pam_container.py cgroups▸

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▸

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▸

QA

http://www.flickr.com/photos/86979666@N00/7623744452