chroot during setup, then container ...
This commit is contained in:
parent
073a4b3704
commit
5c03ed0634
7 changed files with 233 additions and 206 deletions
172
README.md
172
README.md
|
@ -1,161 +1,43 @@
|
|||
## Light Hardened Container
|
||||
|
||||
#### Perché
|
||||
Voglio esporre su internet alcuni servizi da una board (Odroid C2) e farlo a modino, ogni servizio dentro un container.
|
||||
Voglio esporre su internet alcuni servizi da una single board (Odroid C2) e farlo a modino, ogni servizio dentro un container.
|
||||
Giocando con i vari sistemi per creare container quello piú simile ai miei desideri é `runc`.
|
||||
|
||||
#### Come
|
||||
Uso [alpine linux](https://alpinelinux.org) come base perché la rootfs é scandalosamente piccola (1.9Mb), supporta arm64 (che é l'architettura della mia board casalinga), supporta un sistema di pacchetti degno di questo nome (apk) ed e' orientata alla sicurezza.
|
||||
|
||||
L'assunto di base é che i servizi che girano dentro il container sono bucabili e quindi bisogna limitare i danni di un sicuro pwn.
|
||||
Per fare questo ho pensato di far girare la root di ogni container dentro una partizione read-only.
|
||||
Per fare questo ho pensato di far girare la root (/) di ogni container dentro una partizione read-only con un utente specifico per ogni servizio.
|
||||
Per __i dati__ necessari ai vari servizi, faccio un bind di una directory da una partizione no-exec in modo che
|
||||
anche se il servizio viene bucato, l'attaccante puó scrivere solamente sulla partizione dei dati (da cui non puo'
|
||||
peró avviare niente).
|
||||
|
||||
Per evitare di far usare interpreti e altre utilities utili all'attaccante, il container deve contenere esclusivamente i files strettamente necessari per far girare il servizio. Come fare? Partendo dal binario che vogliamo lanciare (sia esso apache, nginx, dovecot o tor) prendiamo innanzitutto le librerie da cui dipende con un `ldd` (anche se sarebbe stato figo usare una distro [tutta statica](http://sta.li)) e poi scopriamo tutti i file da cui dipende cercando le syscall a `open` mentre gira (con `strace`).
|
||||
Per evitare di far usare interpreti e altre utilities utili all'attaccante, il container deve contenere esclusivamente i files strettamente necessari per far girare il servizio, mi buchi ma vuoi usare `ls`? non puoi. vuoi usare `netcat`? non c'é. ok puoi compilarlo statico per `arm64`, auguri, dove lo uploadi? il fs e' read-ony, e in /data e' noexec. Insomma diventa fastidioso.
|
||||
Come fare? ~~Partendo dal binario che vogliamo lanciare (sia esso apache, nginx, dovecot o tor) prendiamo innanzitutto le librerie da cui dipende con un `ldd` (anche se sarebbe stato figo usare una distro [tutta statica](http://sta.li)) e poi scopriamo tutti i file da cui dipende cercando le syscall a `open` mentre gira (con `strace`).~~ Ci serve una lista dei file a cui accede il nostro servizio, servirebbe un proxy fs, quale utilizzo migliore per un filesystem fuse?
|
||||
Cercando in giro trovo ben due implementazioni di proxy fs, [BigBrotherFS](https://www.cs.nmsu.edu/~pfeiffer/fuse-tutorial/) e [https://rflament.github.io/loggedfs/](Loggedfs) che supporta anche i filtri delle syscall quindi piú adatto a questo uso.
|
||||
Le syscall che ci interessano sono le `open` e le `readlink`, quindi il [file di configurazione di loggedfs](config.xml) filtrerá solo queste call, mostrandoci nel file di log solamente i file e i symlink a cui il nostro servizio ha avuto accesso.
|
||||
|
||||
Nella pratica, immaginiamo di voler far girare [caddy](https://caddyserver.com/) in questa maniera, ecco come sarebbe il setup a mano:
|
||||
Per fare tutte queste cose ho scritto uno script bash per evitare di rifare queste cose tutte le volte, vediamo come usarlo:
|
||||
|
||||
## Uso
|
||||
|
||||
Immaginiamo di voler far girare [caddy](https://caddyserver.com/) in questa maniera, diciamo che abbiamo una partizione cifrata dove vogliamo
|
||||
mettere i nostri servizi in `/var/lhc/` con dentro due directory, `containers` e `data`, possiamo lanciare `lhc caddy /var/lhc/containers/ /var/lhc/data`.
|
||||
lhc fará le seguenti operazioni.
|
||||
|
||||
1. crea le dir `/var/lhc/containers/caddy` e `/var/lhc/data/caddy`
|
||||
2. in `/var/lhc/containers/caddy` mette la rootfs di alpine
|
||||
3. crea un utente `caddy` nell'host
|
||||
4. prepara un file di configurazione per lanciare `runc` con i dati di cui sopra
|
||||
5. monta `/var/lhc/containers/caddy` con loggedfs filtrando le chiamate `open` e `readlink`
|
||||
6. lancia una `chroot` dentro `/var/lhc/containers/caddy`
|
||||
6a. qui si aspetta che noi installiamo e configuriamo il servizio
|
||||
7. quando la chroot esce, prende tutti i file aperti, sposta il container originale in `/var/lhc/containers/caddy.orig` e dentro `/var/lhc/containers/caddy` mette solo i file che sono stati aperti.
|
||||
|
||||
il grosso del lavoro che rimane é il punto __6a__, ovvero l'installazione e la configurazione del servizio:
|
||||
|
||||
### Apache setup
|
||||
|
||||
|
||||
Creo una partizione per __i dati__ di 30Mb (a titolo di esempio lo facciamo in loop) e ne faccio il mount (per ora senza noexec)
|
||||
|
||||
```bash
|
||||
dd if=/dev/zero of=./testfs/datafs bs=1024 count=30720
|
||||
losetup /dev/loop0 ./testfs/datafs
|
||||
mkfs.ext4 /dev/loop0
|
||||
mkdir data
|
||||
mount /dev/loop0 data
|
||||
```
|
||||
|
||||
stessa cosa per la partizione dei container (per ora non la monto in read-only)
|
||||
|
||||
```bash
|
||||
dd if=/dev/zero of=./testfs/containerfs bs=1024 count=30720
|
||||
losetup /dev/loop1 ./testfs/containerfs
|
||||
mkfs.ext4 /dev/loop1
|
||||
mkdir containers
|
||||
mount /dev/loop1 containers
|
||||
```
|
||||
|
||||
creo le dir per il container
|
||||
|
||||
```bash
|
||||
mkdir containers/caddy
|
||||
mkdir data/caddy
|
||||
```
|
||||
|
||||
e ci scompatto dentro la rootfs di alpine linux: `tar xvf rootfs/alpine-minirootfs-3.5.1-aarch64.tar.gz -C containers/caddy`
|
||||
ora sará sufficiente `run spec` per creare un file di configurazione di runc e modificare i parametri del file che ci interessano:
|
||||
|
||||
|
||||
```js
|
||||
// prima di tutto il path della rootfs (quindi cercando 'root')
|
||||
"root": {
|
||||
"path": "./containers/caddy",
|
||||
// per ora non lo mettiamo read-only perché dobbiamo prima installare
|
||||
// quello che ci interessa, per il deploy questo bisogna metterlo a true
|
||||
"readonly": false
|
||||
}
|
||||
|
||||
// poi dentro la voce "mounts" aggiungiamo la nostra partizione per i dati
|
||||
"mounts": [
|
||||
{
|
||||
"type": "bind",
|
||||
"destination": "/data",
|
||||
"source": "./data/caddy",
|
||||
"options": ["rbind", "rw", "noexec"]
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
a questo punto possiamo far partire il container con `runc run caddy` e siamo dentro,
|
||||
non rimane che configurare il servizio che ci serve, in questo caso caddy.
|
||||
Potrei fare velocemente con un `apk update` e `apk add caddy` ma il pacchettizzato
|
||||
manca di alcune funzionalitá quindi scelgo di scaricarlo direttamente dal sito:
|
||||
|
||||
```
|
||||
apk update
|
||||
apk add wget
|
||||
wget 'https://caddyserver.com/download/build?os=linux&arch=arm64&features=git,filemanager,cors,expires,minify' -O caddy.tar.gz
|
||||
|
||||
```
|
||||
da adesso in poi, dobbiamo cercare di configurare il servizio per usare /data/ come path per tutti i file che vuole utilizzare in scrittura. Per fare ció possiamo fare in tanti modi, iniziamo a vedere cosa succede ad avviarlo manualmente:
|
||||
|
||||
|
||||
```bash
|
||||
```
|
||||
|
||||
Ora ci serve far partire il container direttamente con `caddy` e non con la shell
|
||||
|
||||
Ultima cosa, non voglio avere una shell dentro il container o altri tool (metti che appunto ci bucano, mica vogliamo fargli un favore), ma come fare? ci serve qualcosa che trovi tutti i file aperti da `caddy` e quello che mi viene in mente é `strace`, quindi da dentro il container installiamo strace (`apk add strace`) e lanciamo nginx con strace redirigendo `stderr` su un file (`strace nginx 2> strace.log`). Dobbiamo cercare di "attivare" tutte le funzionalitá del servizio in modo che becchiamo tutti i file che possono essere utilizzati da `nginx` (in questo caso quello che mi viene in mente é di lanciare una richiesta HTTP a nginx per dire, tipo dall'host faccio un `wget localhost`).
|
||||
Ora killiamo lo strace `kill -9 strace` e cerchiamo le syscallscall a open dentro il log:
|
||||
```bash
|
||||
nginx5:~# grep open strace.log
|
||||
open("/etc/ld-musl-x86_64.path", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
|
||||
open("/lib/libpcre.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
|
||||
open("/usr/local/lib/libpcre.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
|
||||
open("/usr/lib/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
|
||||
open("/lib/libssl.so.39", O_RDONLY|O_CLOEXEC) = 3
|
||||
open("/lib/libcrypto.so.38", O_RDONLY|O_CLOEXEC) = 3
|
||||
open("/lib/libz.so.1", O_RDONLY|O_CLOEXEC) = 3
|
||||
open("/etc/localtime", O_RDONLY|O_NONBLOCK|O_CLOEXEC) = -1 ENOENT (No such file or directory)
|
||||
open("/var/lib/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 3
|
||||
open("/etc/ssl/openssl.cnf", O_RDONLY) = -1 ENOENT (No such file or directory)
|
||||
open("/etc/nginx/nginx.conf", O_RDONLY) = 4
|
||||
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 5
|
||||
open("/etc/group", O_RDONLY|O_CLOEXEC) = 5
|
||||
open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 5
|
||||
open("/etc", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 6
|
||||
open("/etc/nginx", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 7
|
||||
open("/etc/nginx/modules", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 8
|
||||
open("/etc/nginx/mime.types", O_RDONLY) = 5
|
||||
open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 5
|
||||
open("/etc", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 6
|
||||
open("/etc/nginx", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 7
|
||||
open("/etc/nginx/conf.d", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 8
|
||||
open("/etc/nginx/conf.d/default.conf", O_RDONLY) = 5
|
||||
open("/data/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 4
|
||||
open("/var/log/nginx/access.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 5
|
||||
open("/data/nginx.pid", O_RDWR|O_CREAT|O_TRUNC, 0644) = 8
|
||||
nginx5:~#
|
||||
```
|
||||
|
||||
giá guardando gli errori (ENOENT) possiamo vedere alcune cosette, in particolare che ssl non funzionerá (probabilmente manca il pacchetto, ma a noi ora non interessa) e che mi sono dimenticato di cambiare qualche path dei log. comunque, i file mostrati qui sopra sono gli unici che devono rimanere dentro il container per fare in modo che tutti continui a funzionare, quindi estrapoliamo tutti i path:
|
||||
|
||||
```bash
|
||||
nginx:~# grep open strace.log | sed "s/.*\"\(.*\)\".*/\1/" | sort | uniq > needed_files
|
||||
nginx:~# cat needed_files
|
||||
/
|
||||
/data/error.log
|
||||
/data/nginx.pid
|
||||
/etc
|
||||
/etc/group
|
||||
/etc/ld-musl-x86_64.path
|
||||
/etc/localtime
|
||||
/etc/nginx
|
||||
/etc/nginx/conf.d
|
||||
/etc/nginx/conf.d/default.conf
|
||||
/etc/nginx/mime.types
|
||||
/etc/nginx/modules
|
||||
/etc/nginx/nginx.conf
|
||||
/etc/passwd
|
||||
/etc/ssl/openssl.cnf
|
||||
/lib/libcrypto.so.38
|
||||
/lib/libpcre.so.1
|
||||
/lib/libssl.so.39
|
||||
/lib/libz.so.1
|
||||
/usr/lib/libpcre.so.1
|
||||
/usr/local/lib/libpcre.so.1
|
||||
/var/lib/nginx/logs/error.log
|
||||
/var/log/nginx/access.log
|
||||
|
||||
```
|
||||
|
||||
ora, preparo un'altra directory con solo questi files `mkdir containers/nginx-prod` e copio dentro solo i files di cui sopra:
|
||||
|
||||
```bash
|
||||
CONTAINER_ROOT=`pwd`/containers/nginx
|
||||
for f in `cat containers/nginx/root/only_needed` ; do echo $f; if [ -f $CONTAINER_ROOT$f ]; then mkdir -p containers/nginx-prod/`dirname $f` ; cp $CONTAINER_ROOT$f containers/nginx-prod/`dirname $f`; fi; done
|
||||
|
||||
```
|
||||
### Caddy setup
|
160
config.json
Normal file
160
config.json
Normal file
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
"ociVersion": "1.0.0-rc1",
|
||||
"platform": {
|
||||
"os": "linux",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
"process": {
|
||||
"args": ["sh"],
|
||||
"terminal": false,
|
||||
"tty": false,
|
||||
"user": {
|
||||
"uid": 1004,
|
||||
"gid": 1004
|
||||
},
|
||||
"env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"TERM=xterm"
|
||||
],
|
||||
"cwd": "/",
|
||||
"capabilities": [
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_KILL",
|
||||
"CAP_NET_BIND_SERVICE"
|
||||
],
|
||||
"rlimits": [
|
||||
{
|
||||
"type": "RLIMIT_NOFILE",
|
||||
"hard": 1024,
|
||||
"soft": 1024
|
||||
}
|
||||
],
|
||||
"noNewPrivileges": true
|
||||
},
|
||||
"root": {
|
||||
"path": "/tmp/agent/agent",
|
||||
"readonly": true
|
||||
},
|
||||
"mounts": [
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "/tmp/data/agent",
|
||||
"destination": "/data",
|
||||
"options": [ "rbind", "rw", "noexec" ]
|
||||
},
|
||||
{
|
||||
"destination": "/proc",
|
||||
"type": "proc",
|
||||
"source": "proc"
|
||||
},
|
||||
{
|
||||
"destination": "/dev",
|
||||
"type": "tmpfs",
|
||||
"source": "tmpfs",
|
||||
"options": [
|
||||
"nosuid",
|
||||
"strictatime",
|
||||
"mode=755",
|
||||
"size=65536k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/dev/pts",
|
||||
"type": "devpts",
|
||||
"source": "devpts",
|
||||
"options": [
|
||||
"nosuid",
|
||||
"noexec",
|
||||
"newinstance",
|
||||
"ptmxmode=0666",
|
||||
"mode=0620",
|
||||
"gid=5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/dev/shm",
|
||||
"type": "tmpfs",
|
||||
"source": "shm",
|
||||
"options": [
|
||||
"nosuid",
|
||||
"noexec",
|
||||
"nodev",
|
||||
"mode=1777",
|
||||
"size=65536k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/dev/mqueue",
|
||||
"type": "mqueue",
|
||||
"source": "mqueue",
|
||||
"options": [
|
||||
"nosuid",
|
||||
"noexec",
|
||||
"nodev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/sys",
|
||||
"type": "sysfs",
|
||||
"source": "sysfs",
|
||||
"options": [
|
||||
"nosuid",
|
||||
"noexec",
|
||||
"nodev",
|
||||
"ro"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/sys/fs/cgroup",
|
||||
"type": "cgroup",
|
||||
"source": "cgroup",
|
||||
"options": [
|
||||
"nosuid",
|
||||
"noexec",
|
||||
"nodev",
|
||||
"relatime",
|
||||
"ro"
|
||||
]
|
||||
}
|
||||
],
|
||||
"hooks": {},
|
||||
"linux": {
|
||||
"resources": {
|
||||
"devices": [
|
||||
{
|
||||
"allow": false,
|
||||
"access": "rwm"
|
||||
}
|
||||
]
|
||||
},
|
||||
"namespaces": [
|
||||
{
|
||||
"type": "pid"
|
||||
},
|
||||
{
|
||||
"type": "ipc"
|
||||
},
|
||||
{
|
||||
"type": "mount"
|
||||
}
|
||||
],
|
||||
"maskedPaths": [
|
||||
"/proc/kcore",
|
||||
"/proc/latency_stats",
|
||||
"/proc/timer_stats",
|
||||
"/proc/sched_debug"
|
||||
],
|
||||
"readonlyPaths": [
|
||||
"/proc/asound",
|
||||
"/proc/bus",
|
||||
"/proc/fs",
|
||||
"/proc/irq",
|
||||
"/proc/sys",
|
||||
"/proc/sysrq-trigger"
|
||||
]
|
||||
},
|
||||
"solaris": {
|
||||
"cappedCPU": {},
|
||||
"cappedMemory": {}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<loggedFS logEnabled="true" printProcessName="true">
|
||||
<includes>
|
||||
<include extension=".*" uid="*" action="open" retname=".*"/>
|
||||
<include extension=".*" uid="*" action="open" retname="SUCCESS"/>
|
||||
<include extension=".*" uid="*" action="readlink" retname="SUCCESS"/>
|
||||
</includes>
|
||||
<excludes>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
function print_help {
|
||||
echo '''
|
||||
Super Mini hardened container manager using alpine and runc
|
||||
Light Hardened Container / a super light hardened container using alpine and runc
|
||||
v1.0
|
||||
Usage: lhc-create <containername>
|
||||
Usage: lhc <containername> <containerpath> <datapath>
|
||||
'''
|
||||
exit -1
|
||||
}
|
||||
|
@ -29,28 +29,31 @@ print_msg() {
|
|||
TYPE=${msgType:-"[\e[92mInfo\e[0m]"}
|
||||
echo -e $TYPE $CONTENT
|
||||
}
|
||||
|
||||
export ARCH=$(get_arch)
|
||||
print_msg "Arch: $ARCH"
|
||||
|
||||
## check if container's name is passed
|
||||
## TODO, has to check if is not '--help' or '-h'
|
||||
if [ $# -lt 1 ]
|
||||
if [ $# -lt 3 ]
|
||||
then
|
||||
print_help
|
||||
fi
|
||||
|
||||
|
||||
export CONTAINER_NAME=$1
|
||||
export FULL_CONTAINER_PATH="`pwd`/containers/$CONTAINER_NAME/"
|
||||
export FULL_CONTAINER_PATH=`readlink -f $2`/$CONTAINER_NAME
|
||||
export FULL_DATA_PATH=`readlink -f $3`/$CONTAINER_NAME
|
||||
|
||||
print_msg "Container Name: '$CONTAINER_NAME'"
|
||||
print_msg "Creating directory '$FULL_CONTAINER_PATH'"
|
||||
|
||||
mkdir `pwd`/data/$CONTAINER_NAME
|
||||
mkdir `pwd`/containers/$CONTAINER_NAME
|
||||
mkdir $FULL_DATA_PATH
|
||||
mkdir $FULL_CONTAINER_PATH
|
||||
|
||||
print_msg "Decompress alpine rootfs into '$FULL_CONTAINER_PATH'"
|
||||
sudo tar xf rootfs/alpine-minirootfs-3.5.1-$ARCH.tar.gz -C $FULL_CONTAINER_PATH
|
||||
sudo chmod 0755 $FULL_CONTAINER_PATH
|
||||
chmod 0755 $FULL_CONTAINER_PATH
|
||||
|
||||
## set dns
|
||||
echo "nameserver 84.200.70.40" >> $FULL_CONTAINER_PATH/etc/resolv.conf
|
||||
|
@ -61,12 +64,13 @@ print_msg "Create user $CONTAINER_NAME"
|
|||
useradd $CONTAINER_NAME --no-create-home -p=''
|
||||
export CONTAINER_UID=`id $CONTAINER_NAME -u`
|
||||
export CONTAINER_GID=`id $CONTAINER_NAME -g`
|
||||
print_msg "Ok uid: $CONTAINER_UID gid: $CONTAINER_GID"
|
||||
print_msg "uid: $CONTAINER_UID gid: $CONTAINER_GID"
|
||||
|
||||
print_msg "Create container $CONTAINER_NAME"
|
||||
export TERMINAL=false
|
||||
export DEPLOY=true
|
||||
|
||||
#export CAPABILITIES=', "CAP_SYS_ADMIN", "CAP_CHOWN", "CAP_FOWNER", "CAP_NET_RAW", "CAP_SETGID", "CAP_SETUID", "CAP_SYS_CHROOT"'
|
||||
export CAPABILITIES=""
|
||||
|
||||
./runc.template > config.json
|
||||
|
||||
## mount with loggedfs container root
|
||||
|
@ -74,13 +78,13 @@ loggedfs -l files_$CONTAINER_NAME.log -c config.xml -p $FULL_CONTAINER_PATH
|
|||
|
||||
## run chroot
|
||||
print_msg "
|
||||
\n
|
||||
\n\n
|
||||
I'm running chroot now, all opened files will be logged in $CONTAINER_NAME.log\n
|
||||
\n
|
||||
- Install and setup your stuff, if you need some package use 'apk update' and 'apk search'\n
|
||||
- Configure your process to use /data as storage point (/ will be read-only)\n
|
||||
- Clean $CONTAINER_NAME.log 'echo "" > $CONTAINER_NAME.log'\n
|
||||
- Start your process, exit on done!\n\n
|
||||
- Configure your process to use /data as storage path (/ will be read-only)\n
|
||||
- Clean $CONTAINER_NAME.log from host machine: 'echo "" > $CONTAINER_NAME.log'\n
|
||||
- Start your process and try to activate funtionality, exit on done!\n\n
|
||||
|
||||
"
|
||||
|
||||
|
@ -89,61 +93,45 @@ mount -t sysfs sys $FULL_CONTAINER_PATH/sys/
|
|||
mount -o bind /dev $FULL_CONTAINER_PATH/dev/
|
||||
|
||||
chroot $FULL_CONTAINER_PATH sh
|
||||
|
||||
## let's copy all used files/symlink in a new shiny dir
|
||||
|
||||
escaped_path=$(echo $FULL_CONTAINER_PATH | sed -e 's/\//\\\//g')
|
||||
echo "ESCAPED_PATH: $escaped_path"
|
||||
mkdir `pwd`/containers/$CONTAINER_NAME.tmp
|
||||
mkdir $FULL_CONTAINER_PATH.tmp
|
||||
|
||||
files=`sed -rn "s/.* open (readwrite |writeonly )?$escaped_path(.*) \{.*/\2/p" < files_$CONTAINER_NAME.log | sort | uniq`
|
||||
links=`sed -rn "s/.* readlink $escaped_path(.*) \{.*/\1/p" < files_$CONTAINER_NAME.log | sort | uniq`
|
||||
files=`sed -rn "s/.* open (readwrite |writeonly )?$escaped_path\/?(.*) \{.*/\2/p" < files_$CONTAINER_NAME.log | sort | uniq`
|
||||
links=`sed -rn "s/.* readlink $escaped_path\/?(.*) \{.*/\1/p" < files_$CONTAINER_NAME.log | sort | uniq`
|
||||
|
||||
## ok, removing all file but ones in $CONTAINER_NAME.log
|
||||
cd $FULL_CONTAINER_PATH
|
||||
for f in $files; do
|
||||
echo $f
|
||||
cp --parents $f ../$CONTAINER_NAME.tmp/
|
||||
cp --parents $f $FULL_CONTAINER_PATH.tmp/
|
||||
done
|
||||
|
||||
for l in $links; do
|
||||
to=$(ls -la $l | sed -rn "s/.*-> (.*)/\1/p")
|
||||
echo "$l -> $to"
|
||||
ln -s $to ../$CONTAINER_NAME.tmp/$l
|
||||
ln -s $to $FULL_CONTAINER_PATH.tmp/$l
|
||||
done
|
||||
|
||||
|
||||
|
||||
cd ..
|
||||
cd -
|
||||
umount $FULL_CONTAINER_PATH/proc
|
||||
umount $FULL_CONTAINER_PATH/dev
|
||||
umount $FULL_CONTAINER_PATH/sys
|
||||
umount $FULL_CONTAINER_PATH
|
||||
|
||||
#export TERMINAL=true
|
||||
#export DEPLOY=false
|
||||
#export CAPABILITIES=', "CAP_SYS_ADMIN", "CAP_CHOWN", "CAP_FOWNER", "CAP_NET_RAW", "CAP_SETGID", "CAP_SETUID", "CAP_SYS_CHROOT"'
|
||||
#CONTAINER_UID=0
|
||||
#CONTAINER_GID=0
|
||||
#./runc.template > config.dev.json
|
||||
ORIG_SIZE=`du -hs $FULL_CONTAINER_PATH`
|
||||
LHC_SIZE=`du -hs $FULL_CONTAINER_PATH.tmp`
|
||||
|
||||
print_msg "ORIGINAL CONTAINER SIZE: `du -hs $FULL_CONTAINER_PATH` // N_FILES: `find $FULL_CONTAINER_PATH | wc -l`"
|
||||
print_msg "LHC CONTAINER SIZE: `du -hs $FULL_CONTAINER_PATH.tmp` // N_FILES: `find $FULL_CONTAINER_PATH.tmp | wc -l`"
|
||||
|
||||
mv $FULL_CONTAINER_PATH $FULL_CONTAINER_PATH.orig
|
||||
mv $FULL_CONTAINER_PATH.tmp $FULL_CONTAINER_PATH
|
||||
|
||||
print_msg "Place specify your init command in config.json and try to run 'runc run $CONTAINER_NAME'$"
|
||||
cp config.json runc.config/$CONTAINER_NAME.json
|
||||
|
||||
|
||||
|
||||
#print_msg "Patch inittab"
|
||||
## modify inittab to fix alpine tty/console issue!
|
||||
## comment all ttyN respawn lines
|
||||
#sudo sed -i "s/^.*respawn:\/sbin\/getty.*/#&/" $fullContainerPath/etc/inittab
|
||||
|
||||
## and add a line for a console
|
||||
#sudo bash -c 'echo "console::respawn:/sbin/getty 38400 /dev/console" >> $fullContainerPath/etc/inittab'
|
||||
|
||||
#print_msg "Update package"
|
||||
## update package
|
||||
#sudo systemd-nspawn -D $fullContainerPath -M $containerName apk update
|
||||
#print_msg "Install vim / git"
|
||||
#sudo systemd-nspawn -D $fullContainerPath -M $containerName apk add vim git openrc
|
||||
#print_msg "Ready"
|
||||
#sudo systemd-nspawn -bD $fullContainerPath -M $containerName
|
||||
|
||||
|
||||
|
||||
##
|
||||
|
||||
#sed "s/.*\"\(.*\)\".*/\1/" file
|
||||
###### CHECK #####
|
BIN
rootfs/alpine-minirootfs-3.5.1-aarch64.tar.gz
Normal file
BIN
rootfs/alpine-minirootfs-3.5.1-aarch64.tar.gz
Normal file
Binary file not shown.
BIN
rootfs/alpine-minirootfs-3.5.1-x86_64.tar.gz
Normal file
BIN
rootfs/alpine-minirootfs-3.5.1-x86_64.tar.gz
Normal file
Binary file not shown.
|
@ -7,15 +7,13 @@ cat <<EOF
|
|||
"arch": "$ARCH"
|
||||
},
|
||||
"process": {
|
||||
"terminal": $TERMINAL,
|
||||
"tty": true,
|
||||
"args": ["sh"],
|
||||
"terminal": false,
|
||||
"tty": false,
|
||||
"user": {
|
||||
"uid": $CONTAINER_UID,
|
||||
"gid": $CONTAINER_GID
|
||||
},
|
||||
"args": [
|
||||
"sh"
|
||||
],
|
||||
"env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"TERM=xterm"
|
||||
|
@ -25,7 +23,6 @@ cat <<EOF
|
|||
"CAP_AUDIT_WRITE",
|
||||
"CAP_KILL",
|
||||
"CAP_NET_BIND_SERVICE"
|
||||
$CAPABILITIES
|
||||
],
|
||||
"rlimits": [
|
||||
{
|
||||
|
@ -37,13 +34,13 @@ cat <<EOF
|
|||
"noNewPrivileges": true
|
||||
},
|
||||
"root": {
|
||||
"path": "./containers/$CONTAINER_NAME",
|
||||
"readonly": $DEPLOY
|
||||
"path": "$FULL_CONTAINER_PATH",
|
||||
"readonly": true
|
||||
},
|
||||
"mounts": [
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "./data/$CONTAINER_NAME",
|
||||
"source": "$FULL_DATA_PATH",
|
||||
"destination": "/data",
|
||||
"options": [ "rbind", "rw", "noexec" ]
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue