mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 05:19:39 +02:00
feat(dockerui): add support for TLS enabled engines (#63)
This commit is contained in:
parent
e67e20ce18
commit
1fb008212a
3 changed files with 66 additions and 5 deletions
14
README.md
14
README.md
|
@ -54,6 +54,19 @@ UI For Docker listens on port 9000 by default. If you run UI For Docker inside a
|
||||||
$ docker run -d -p 10.20.30.1:80:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock cloudinovasi/cloudinovasi-ui
|
$ docker run -d -p 10.20.30.1:80:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock cloudinovasi/cloudinovasi-ui
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Access a Docker engine protected via TLS
|
||||||
|
|
||||||
|
Ensure that you have access to the CA, the cert and the public key used to access your Docker engine.
|
||||||
|
|
||||||
|
These files will need to be named `ca.pem`, `cert.pem` and `key.pem` respectively. Store them somewhere on your disk and mount a volume containing these files inside the UI container:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Note the access to the endpoint via https
|
||||||
|
$ docker run -d -p 9000:9000 cloudinovasi/cloudinovasi-ui -v /path/to/certs:/certs -e https://my-docker-host.domain:2376
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note*: Replace `/path/to/certs` to the path to the certificate files on your disk.
|
||||||
|
|
||||||
### Hide containers with specific labels
|
### Hide containers with specific labels
|
||||||
|
|
||||||
You can hide specific containers in the containers view by using the `-hide-label` or `-l` options and specifying a label.
|
You can hide specific containers in the containers view by using the `-hide-label` or `-l` options and specifying a label.
|
||||||
|
@ -77,6 +90,7 @@ The following options are available for the `ui-for-docker` binary:
|
||||||
* `--endpoint`, `-e`: Docker deamon endpoint (default: *"/var/run/docker.sock"*)
|
* `--endpoint`, `-e`: Docker deamon endpoint (default: *"/var/run/docker.sock"*)
|
||||||
* `--bind`, `-p`: Address and port to serve UI For Docker (default: *":9000"*)
|
* `--bind`, `-p`: Address and port to serve UI For Docker (default: *":9000"*)
|
||||||
* `--data`, `-d`: Path to the data folder (default: *"."*)
|
* `--data`, `-d`: Path to the data folder (default: *"."*)
|
||||||
|
* `--certs`, `-c`: Path to the certificates used for TLS (default: *"/certs"*)
|
||||||
* `--assets`, `-a`: Path to the assets (default: *"."*)
|
* `--assets`, `-a`: Path to the assets (default: *"."*)
|
||||||
* `--swarm`, `-s`: Swarm cluster support (default: *false*)
|
* `--swarm`, `-s`: Swarm cluster support (default: *false*)
|
||||||
* `--hide-label`, `-l`: Hide containers with a specific label in the UI
|
* `--hide-label`, `-l`: Hide containers with a specific label in the UI
|
||||||
|
|
43
dockerui.go
43
dockerui.go
|
@ -15,6 +15,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -22,6 +24,7 @@ var (
|
||||||
addr = kingpin.Flag("bind", "Address and port to serve UI For Docker").Default(":9000").Short('p').String()
|
addr = kingpin.Flag("bind", "Address and port to serve UI For Docker").Default(":9000").Short('p').String()
|
||||||
assets = kingpin.Flag("assets", "Path to the assets").Default(".").Short('a').String()
|
assets = kingpin.Flag("assets", "Path to the assets").Default(".").Short('a').String()
|
||||||
data = kingpin.Flag("data", "Path to the data").Default(".").Short('d').String()
|
data = kingpin.Flag("data", "Path to the data").Default(".").Short('d').String()
|
||||||
|
certs = kingpin.Flag("certs", "Path to the certs").Default("/certs").Short('c').String()
|
||||||
swarm = kingpin.Flag("swarm", "Swarm cluster support").Default("false").Short('s').Bool()
|
swarm = kingpin.Flag("swarm", "Swarm cluster support").Default("false").Short('s').Bool()
|
||||||
labels = LabelParser(kingpin.Flag("hide-label", "Hide containers with a specific label in the UI").Short('l'))
|
labels = LabelParser(kingpin.Flag("hide-label", "Hide containers with a specific label in the UI").Short('l'))
|
||||||
authKey []byte
|
authKey []byte
|
||||||
|
@ -114,18 +117,50 @@ func createTcpHandler(e string) http.Handler {
|
||||||
return httputil.NewSingleHostReverseProxy(u)
|
return httputil.NewSingleHostReverseProxy(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createTlsConfig(c string) *tls.Config {
|
||||||
|
cert, err := tls.LoadX509KeyPair(c + "/" + "cert.pem", c + "/" + "key.pem")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
caCert, err := ioutil.ReadFile(c + "/" + "ca.pem")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
}
|
||||||
|
return tlsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTcpHandlerWithTLS(e string, c string) http.Handler {
|
||||||
|
u, err := url.Parse(e)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
var tlsConfig = createTlsConfig(c)
|
||||||
|
proxy := httputil.NewSingleHostReverseProxy(u)
|
||||||
|
proxy.Transport = &http.Transport{
|
||||||
|
TLSClientConfig: tlsConfig,
|
||||||
|
}
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
func createUnixHandler(e string) http.Handler {
|
func createUnixHandler(e string) http.Handler {
|
||||||
return &UnixHandler{e}
|
return &UnixHandler{e}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHandler(dir string, d string, e string, c Config) http.Handler {
|
func createHandler(dir string, d string, certs string, e string, c Config) http.Handler {
|
||||||
var (
|
var (
|
||||||
mux = http.NewServeMux()
|
mux = http.NewServeMux()
|
||||||
fileHandler = http.FileServer(http.Dir(dir))
|
fileHandler = http.FileServer(http.Dir(dir))
|
||||||
h http.Handler
|
h http.Handler
|
||||||
)
|
)
|
||||||
|
if strings.Contains(e, "https") {
|
||||||
if strings.Contains(e, "http") {
|
h = createTcpHandlerWithTLS(e, certs)
|
||||||
|
} else if strings.Contains(e, "http") {
|
||||||
h = createTcpHandler(e)
|
h = createTcpHandler(e)
|
||||||
} else {
|
} else {
|
||||||
if _, err := os.Stat(e); err != nil {
|
if _, err := os.Stat(e); err != nil {
|
||||||
|
@ -181,7 +216,7 @@ func main() {
|
||||||
HiddenLabels: *labels,
|
HiddenLabels: *labels,
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := createHandler(*assets, *data, *endpoint, configuration)
|
handler := createHandler(*assets, *data, *certs, *endpoint, configuration)
|
||||||
if err := http.ListenAndServe(*addr, handler); err != nil {
|
if err := http.ListenAndServe(*addr, handler); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
14
gruntFile.js
14
gruntFile.js
|
@ -40,6 +40,7 @@ module.exports = function (grunt) {
|
||||||
grunt.registerTask('run', ['if:binaryNotExist', 'build', 'shell:buildImage', 'shell:run']);
|
grunt.registerTask('run', ['if:binaryNotExist', 'build', 'shell:buildImage', 'shell:run']);
|
||||||
grunt.registerTask('run-swarm', ['if:binaryNotExist', 'build', 'shell:buildImage', 'shell:runSwarm', 'watch:buildSwarm']);
|
grunt.registerTask('run-swarm', ['if:binaryNotExist', 'build', 'shell:buildImage', 'shell:runSwarm', 'watch:buildSwarm']);
|
||||||
grunt.registerTask('run-dev', ['if:binaryNotExist', 'shell:buildImage', 'shell:run', 'watch:build']);
|
grunt.registerTask('run-dev', ['if:binaryNotExist', 'shell:buildImage', 'shell:run', 'watch:build']);
|
||||||
|
grunt.registerTask('run-ssl', ['if:binaryNotExist', 'shell:buildImage', 'shell:runSsl', 'watch:buildSsl']);
|
||||||
grunt.registerTask('clear', ['clean:app']);
|
grunt.registerTask('clear', ['clean:app']);
|
||||||
|
|
||||||
// Print a timestamp (useful for when watching)
|
// Print a timestamp (useful for when watching)
|
||||||
|
@ -224,6 +225,10 @@ module.exports = function (grunt) {
|
||||||
buildSwarm: {
|
buildSwarm: {
|
||||||
files: ['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'],
|
files: ['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'],
|
||||||
tasks: ['build', 'shell:buildImage', 'shell:runSwarm', 'shell:cleanImages']
|
tasks: ['build', 'shell:buildImage', 'shell:runSwarm', 'shell:cleanImages']
|
||||||
|
},
|
||||||
|
buildSsl: {
|
||||||
|
files: ['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'],
|
||||||
|
tasks: ['build', 'shell:buildImage', 'shell:runSsl', 'shell:cleanImages']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
jshint: {
|
jshint: {
|
||||||
|
@ -267,7 +272,14 @@ module.exports = function (grunt) {
|
||||||
command: [
|
command: [
|
||||||
'docker stop ui-for-docker',
|
'docker stop ui-for-docker',
|
||||||
'docker rm ui-for-docker',
|
'docker rm ui-for-docker',
|
||||||
'docker run --privileged -d -p 9000:9000 -v /tmp/docker-ui:/data --name ui-for-docker ui-for-docker -e http://10.0.7.10:4000 --swarm -d /data'
|
'docker run -d -p 9000:9000 -v /tmp/docker-ui:/data --name ui-for-docker ui-for-docker -e http://10.0.7.10:4000 --swarm -d /data'
|
||||||
|
].join(';')
|
||||||
|
},
|
||||||
|
runSsl: {
|
||||||
|
command: [
|
||||||
|
'docker stop ui-for-docker',
|
||||||
|
'docker rm ui-for-docker',
|
||||||
|
'docker run -d -p 9000:9000 -v /tmp/docker-ui:/data -v /tmp/docker-ssl:/certs --name ui-for-docker ui-for-docker -e https://10.0.7.10:2376 -d /data'
|
||||||
].join(';')
|
].join(';')
|
||||||
},
|
},
|
||||||
cleanImages: {
|
cleanImages: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue