parent
bdaebcc92f
commit
82bb795b85
9 changed files with 334 additions and 86 deletions
@ -0,0 +1,71 @@ |
|||||||
|
module.exports = function(config) { |
||||||
|
|
||||||
|
const crypto = require('crypto'); |
||||||
|
const password = crypto.randomBytes(256); |
||||||
|
var cookie = require('cookie-encryption'); |
||||||
|
// const cipher = crypto.createCipher('aes256', password);
|
||||||
|
// const decipher = crypto.createDecipher('aes256', password);
|
||||||
|
// var encrypted = cipher.update(JSON.stringify(user), 'utf8', 'base64')
|
||||||
|
// + cipher.final('base64');
|
||||||
|
// console.log("encrypted", encrypted);
|
||||||
|
// var decrypted = decipher.update(encrypted, 'base64', 'utf8') + decipher.final('utf8');
|
||||||
|
// console.log("decrypted", decrypted);
|
||||||
|
|
||||||
|
var authentication = function (req, res, next) { |
||||||
|
return next(); |
||||||
|
} |
||||||
|
|
||||||
|
if (config) { |
||||||
|
|
||||||
|
var cipher = config.cookies && config.cookies.cipher ? config.cookies.cipher : "aes256"; |
||||||
|
|
||||||
|
authentication = function (req, res, next) { |
||||||
|
|
||||||
|
function unauthorized(res) { |
||||||
|
res.setHeader('WWW-Authenticate', 'Basic realm=Authorization Required'); |
||||||
|
res.status(401).send('Not logged in. <a href="/">Login</a>'); |
||||||
|
}; |
||||||
|
|
||||||
|
var user = require('basic-auth')(req); |
||||||
|
var vault = cookie('credentials'); |
||||||
|
|
||||||
|
if (!user || !user.name || !user.pass) { |
||||||
|
return unauthorized(res); |
||||||
|
}; |
||||||
|
|
||||||
|
if (config.passwords && config.passwords[user.name]) { |
||||||
|
if (crypto.getHashes().indexOf(config.passwords[user.name][0])>=0) { |
||||||
|
if (crypto.createHash(config.passwords[user.name][0]) |
||||||
|
.update(user.pass, 'utf8').digest('hex') === config.passwords[user.name][1]) { |
||||||
|
return next(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
console.log("**** HASH NOT FOUND ****"); |
||||||
|
console.log(config.passwords[user.name][0]); |
||||||
|
console.log(crypto.getHashes()); |
||||||
|
} |
||||||
|
} |
||||||
|
if (config.ldap) try { |
||||||
|
var LdapAuth = require('ldapauth'); |
||||||
|
var auth = new LdapAuth(config.ldap); |
||||||
|
auth.authenticate(user.name, user.pass, function(err, usr) { |
||||||
|
auth.close(function(err) {}) |
||||||
|
if (err) { |
||||||
|
console.log("**** ERROR: LDAP Authentication failed:", err); |
||||||
|
return unauthorized(res); |
||||||
|
} |
||||||
|
console.log("**** SUCCESS: LDAP Authentication:"); |
||||||
|
return next(); |
||||||
|
}); |
||||||
|
return; // need to block here!
|
||||||
|
} catch (e) { |
||||||
|
console.log("**** Error: LDAP failed: ", e, e.stack); |
||||||
|
} |
||||||
|
return unauthorized(res); |
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
return authentication; |
||||||
|
|
||||||
|
} |
@ -1,3 +1,23 @@ |
|||||||
{ |
{ |
||||||
"port": 8888 |
"port": 8888, |
||||||
|
"restrict": { |
||||||
|
"cookies": { |
||||||
|
"cipher": "aes256" |
||||||
|
}, |
||||||
|
"passwords": { |
||||||
|
"marc": ["sha256", "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], |
||||||
|
"foo": ["sha256", "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"] |
||||||
|
}, |
||||||
|
"ldap": { |
||||||
|
"tlsOptions": { |
||||||
|
"requestCert": false, |
||||||
|
"rejectUnauthorized": false |
||||||
|
}, |
||||||
|
"url": "ldap://dev.marc.waeckerlin.org", |
||||||
|
"adminDn": "cn=tmp,ou=system,ou=people,dc=dev,dc=marc,dc=waeckerlin,dc=org", |
||||||
|
"adminPassword": "dGg7benUnZ9z", |
||||||
|
"searchBase": "ou=person,ou=people,dc=dev,dc=marc,dc=waeckerlin,dc=org", |
||||||
|
"searchFilter": "(uid={{username}})" |
||||||
|
} |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -1,30 +1,33 @@ |
|||||||
{ |
{ |
||||||
"name": "@PACKAGE_NAME@", |
"name": "@PACKAGE_NAME@", |
||||||
"version": "@PACKAGE_VERSION@", |
"version": "@PACKAGE_VERSION@", |
||||||
"private": true, |
"private": true, |
||||||
"dependencies": { |
"description": "Docker as a Service", |
||||||
"express": "~2.5.8", |
"main": "servicedock.js", |
||||||
"stylus": "~0.53.0", |
"devDependencies": {}, |
||||||
"ejs": ">= 0.0.1", |
"scripts": { |
||||||
"socket.io": "~1.4.4", |
"test": "echo \"Error: no test specified\" && exit 1" |
||||||
"pty.js": "~0.3.0", |
}, |
||||||
"async": "~1.5.2" |
"author": "Marc Wäckerlin", |
||||||
}, |
"license": "LGPL3", |
||||||
"description": "Docker as a Service", |
"path": { |
||||||
"main": "servicedock.js", |
"prefix": "@PREFIX@", |
||||||
"devDependencies": {}, |
"sysconf": "@SYSCONFDIR@", |
||||||
"scripts": { |
"pkgdata": "@PKGDATADIR@", |
||||||
"test": "echo \"Error: no test specified\" && exit 1" |
"localstate": "@LOCALSTATEDIR@", |
||||||
}, |
"log": "@LOCALSTATEDIR@/log/@PACKAGE_NAME@.log", |
||||||
"author": "Marc Wäckerlin", |
"config": "@SYSCONFDIR@/@PACKAGE_NAME@.json", |
||||||
"license": "LGPL3", |
"nodejs": "@PKGDATADIR@/nodejs" |
||||||
"path": { |
}, |
||||||
"prefix": "@PREFIX@", |
"dependencies": { |
||||||
"sysconf": "@SYSCONFDIR@", |
"express": "~2.5.8", |
||||||
"pkgdata": "@PKGDATADIR@", |
"stylus": "~0.53.0", |
||||||
"localstate": "@LOCALSTATEDIR@", |
"ejs": ">= 0.0.1", |
||||||
"log": "@LOCALSTATEDIR@/log/@PACKAGE_NAME@.log", |
"socket.io": "~1.4.4", |
||||||
"config": "@SYSCONFDIR@/@PACKAGE_NAME@.json", |
"pty.js": "~0.3.0", |
||||||
"nodejs": "@PKGDATADIR@/nodejs" |
"async": "~1.5.2", |
||||||
} |
"basic-auth": "~1.0.3", |
||||||
|
"ldapauth": "~2.2.4", |
||||||
|
"cookie-encryption": "~1.4.2" |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -1,55 +1,69 @@ |
|||||||
|
try { |
||||||
|
|
||||||
/** |
process.on('uncaughtException', function(e) { |
||||||
* Module dependencies. |
console.log("**** UNCAUGHT EXCEPTION ****"); |
||||||
*/ |
console.log(e); |
||||||
|
console.log(e.stack); |
||||||
var express = require('express') |
|
||||||
, routes = require(__dirname+'/routes'); |
|
||||||
|
|
||||||
var app = module.exports = express.createServer(); |
|
||||||
var io = require('socket.io').listen(app); |
|
||||||
var sockets = require(__dirname+'/sockets')(io); |
|
||||||
var package = require(__dirname+'/package.json'); |
|
||||||
var config = require(package.path.config); |
|
||||||
var docker = require(__dirname+'/docker')(app); |
|
||||||
|
|
||||||
// Configuration
|
|
||||||
process.argv.forEach(function(val, index) { |
|
||||||
if (index<2) {return} |
|
||||||
if (index!=2 || typeof val != 'number') { |
|
||||||
console.log("**** ERROR: Unexpected Argument - allowed is only a port number"); |
|
||||||
process.exit(1); |
process.exit(1); |
||||||
} |
}); |
||||||
config.port = val; |
|
||||||
}); |
/** |
||||||
if (typeof config.port != 'number') { |
* Module dependencies. |
||||||
console.log("**** WARNING: no valid port given, defaults to 8888"); |
*/ |
||||||
config.port = 8888; |
|
||||||
} |
var express = require('express') |
||||||
|
, routes = require(__dirname+'/routes'); |
||||||
|
|
||||||
app.configure(function(){ |
var app = module.exports = express.createServer(); |
||||||
app.set('views', __dirname + '/views'); |
var io = require('socket.io').listen(app); |
||||||
app.set('view engine', 'ejs'); |
var sockets = require(__dirname+'/sockets')(io); |
||||||
app.use(express.bodyParser()); |
var package = require(__dirname+'/package.json'); |
||||||
app.use(express.methodOverride()); |
var config = require(package.path.config); |
||||||
app.use(require('stylus').middleware({ src: __dirname + '/public' })); |
var docker = require(__dirname+'/docker')(app); |
||||||
app.use(app.router); |
var authentication = require(__dirname+'/authentication')(config.restrict); |
||||||
app.use(express.static(__dirname + '/public')); |
|
||||||
}); |
|
||||||
|
|
||||||
app.configure('development', function(){ |
// Configuration
|
||||||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); |
process.argv.forEach(function(val, index) { |
||||||
}); |
if (index<2) {return} |
||||||
|
if (index!=2 || typeof val != 'number') { |
||||||
|
console.log("**** ERROR: Unexpected Argument - allowed is only a port number"); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
config.port = val; |
||||||
|
}); |
||||||
|
if (typeof config.port != 'number') { |
||||||
|
console.log("**** WARNING: no valid port given, defaults to 8888"); |
||||||
|
config.port = 8888; |
||||||
|
} |
||||||
|
|
||||||
|
app.configure(function(){ |
||||||
|
app.set('views', __dirname + '/views'); |
||||||
|
app.set('view engine', 'ejs'); |
||||||
|
app.use(express.bodyParser()); |
||||||
|
app.use(express.methodOverride()); |
||||||
|
app.use(require('stylus').middleware({ src: __dirname + '/public' })); |
||||||
|
app.use(app.router); |
||||||
|
app.use(express.static(__dirname + '/public')); |
||||||
|
}); |
||||||
|
|
||||||
app.configure('production', function(){ |
app.configure('development', function(){ |
||||||
app.use(express.errorHandler()); |
app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); |
||||||
}); |
}); |
||||||
|
|
||||||
// Routes
|
app.configure('production', function(){ |
||||||
|
app.use(express.errorHandler()); |
||||||
|
}); |
||||||
|
|
||||||
app.get('/', routes.index); |
// Routes
|
||||||
|
app.get('/', authentication, routes.index); |
||||||
|
|
||||||
app.listen(config.port, function() { |
app.listen(config.port, function() { |
||||||
console.log("Express server listening on port %d in %s mode", |
console.log("Express server listening on port %d in %s mode", |
||||||
app.address().port, app.settings.env); |
app.address().port, app.settings.env); |
||||||
}); |
}); |
||||||
|
} catch (e) { |
||||||
|
console.log("**** EXCEPTION ****"); |
||||||
|
console.log(e); |
||||||
|
console.log(e.stack); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
@ -0,0 +1,129 @@ |
|||||||
|
#!/bin/bash -e |
||||||
|
|
||||||
|
function get-volumes() { |
||||||
|
local vols="" |
||||||
|
for vol in ${*}; do |
||||||
|
local vf=$(docker inspect -f '{{.HostConfig.VolumesFrom}}' ${vol} | sed -n 's,^\[\(.*\)\]$,\1,p') |
||||||
|
if test -n "$vf"; then |
||||||
|
vols+=" "$(get-volumes $vf) |
||||||
|
fi |
||||||
|
vols+=" "$(docker inspect -f '{{.Config.Volumes}}' ${vol} | sed -n 's,^map\[\(.*\)\]$,\1,p' | sed 's,:[^ ]*,,g') |
||||||
|
done |
||||||
|
echo ${vols} | tr '[ ]' '[\n]' | sort | uniq | tr '[\n]' '[ ]' |
||||||
|
} |
||||||
|
|
||||||
|
backup="" |
||||||
|
volumes="" |
||||||
|
infile="" |
||||||
|
tofile="" |
||||||
|
toserver="" |
||||||
|
tocontainer="" |
||||||
|
while test $# -gt 0; do |
||||||
|
case "$1" in |
||||||
|
(-h|--help) |
||||||
|
cat <<EOF |
||||||
|
$0 -b [OPTIONS] |
||||||
|
|
||||||
|
OPTIONS: |
||||||
|
-b, --backup <container> name of the docker container to backup |
||||||
|
-v, --volume <volume> add volume path to backup from container |
||||||
|
-a, --auto automatically detect volumes to backup from container |
||||||
|
-i, --in-file <file> take already existing backup file to import |
||||||
|
-s, --to-server <server> copy backup to docker instance on ssh server |
||||||
|
-c, --to-container <container> write backup into container on ssh server |
||||||
|
-o, --to-file <file> write backup to file |
||||||
|
|
||||||
|
DESCRIPTION: |
||||||
|
|
||||||
|
Take docker backups and copy them to a file or restore them into a |
||||||
|
docker instance on an ssh target server. |
||||||
|
|
||||||
|
Note: Use ssh key exchange to prevent password query. |
||||||
|
Note: Only volume paths are backed-up correctly |
||||||
|
|
||||||
|
EXAMPLE: |
||||||
|
|
||||||
|
$0 -b wordpress -a -o /tmp/wordpress.bak.tar.bz2 |
||||||
|
$0 -i /tmp/wordpress.bak.tar.bz2 -c wordpress |
||||||
|
$0 -b backup-test -a -s server -c backup-test |
||||||
|
|
||||||
|
EOF |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
(-b|--backup) |
||||||
|
shift |
||||||
|
backup="$1" |
||||||
|
;; |
||||||
|
(-i|--in-file) |
||||||
|
shift |
||||||
|
infile="$1" |
||||||
|
;; |
||||||
|
(-o|--to-file) |
||||||
|
shift |
||||||
|
tofile="$1" |
||||||
|
;; |
||||||
|
(-s|--to-server) |
||||||
|
shift |
||||||
|
toserver="$1" |
||||||
|
;; |
||||||
|
(-c|--to-container) |
||||||
|
shift |
||||||
|
tocontainer="$1" |
||||||
|
;; |
||||||
|
(-a|--auto) |
||||||
|
if test -z "$backup"; then |
||||||
|
echo "**** Error: --auto first requires --backup, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
volumes+=" "$(get-volumes $backup) |
||||||
|
;; |
||||||
|
(-v|--volume) |
||||||
|
shift |
||||||
|
volumes+=("$1") |
||||||
|
;; |
||||||
|
(*) |
||||||
|
echo "**** Error: unknown argument $1, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
;; |
||||||
|
esac |
||||||
|
if test $# -eq 0; then |
||||||
|
echo "**** Error: missing argument, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
shift |
||||||
|
done |
||||||
|
|
||||||
|
if test -n "$backup"; then |
||||||
|
if test -z "${volumes}"; then |
||||||
|
echo "**** Error: no volumes to backup, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
elif test -z "$infile"; then |
||||||
|
echo "**** Error: no input source specified, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
if test -n "$toserver"; then |
||||||
|
if test -z "$tocontainer"; then |
||||||
|
echo "**** Error: no target container specified, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
elif test -z "$tofile" -a -z "$tocontainer";then |
||||||
|
echo "**** Error: no target specified, try $0 --help" 1>&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
( |
||||||
|
if test -n "$backup"; then |
||||||
|
docker run --rm -i -w / --volumes-from $backup ubuntu tar cjP ${volumes} |
||||||
|
elif test -n "$infile"; then |
||||||
|
cat "$infile" |
||||||
|
fi |
||||||
|
) | ( |
||||||
|
if test -n "$toserver"; then |
||||||
|
ssh $toserver docker run --rm -i -w / --volumes-from $tocontainer ubuntu tar xjP |
||||||
|
elif test -n "$tocontainer"; then |
||||||
|
docker run --rm -i -w / --volumes-from $tocontainer ubuntu tar xjP |
||||||
|
elif test -n "$tofile";then |
||||||
|
cat > "$tofile" |
||||||
|
fi |
||||||
|
) |
Loading…
Reference in new issue