From 145f020122681d4868f717d64dfa556db22ac83d Mon Sep 17 00:00:00 2001 From: David Calavera Date: Fri, 8 Jan 2016 12:35:35 -0500 Subject: [PATCH 1/2] Vendor new syslog library with TLS support. The syslog package in the stdlib is not maintained anymore. Signed-off-by: David Calavera --- hack/vendor.sh | 1 + .../src/github.com/RackSec/srslog/.gitignore | 1 + .../src/github.com/RackSec/srslog/.travis.yml | 13 ++ .../RackSec/srslog/CODE_OF_CONDUCT.md | 50 ++++++ vendor/src/github.com/RackSec/srslog/LICENSE | 27 ++++ .../src/github.com/RackSec/srslog/README.md | 131 +++++++++++++++ .../github.com/RackSec/srslog/constants.go | 68 ++++++++ .../src/github.com/RackSec/srslog/dialer.go | 53 ++++++ .../src/github.com/RackSec/srslog/net_conn.go | 24 +++ .../src/github.com/RackSec/srslog/srslog.go | 96 +++++++++++ .../github.com/RackSec/srslog/srslog_unix.go | 47 ++++++ .../src/github.com/RackSec/srslog/writer.go | 152 ++++++++++++++++++ 12 files changed, 663 insertions(+) create mode 100644 vendor/src/github.com/RackSec/srslog/.gitignore create mode 100644 vendor/src/github.com/RackSec/srslog/.travis.yml create mode 100644 vendor/src/github.com/RackSec/srslog/CODE_OF_CONDUCT.md create mode 100644 vendor/src/github.com/RackSec/srslog/LICENSE create mode 100644 vendor/src/github.com/RackSec/srslog/README.md create mode 100644 vendor/src/github.com/RackSec/srslog/constants.go create mode 100644 vendor/src/github.com/RackSec/srslog/dialer.go create mode 100644 vendor/src/github.com/RackSec/srslog/net_conn.go create mode 100644 vendor/src/github.com/RackSec/srslog/srslog.go create mode 100644 vendor/src/github.com/RackSec/srslog/srslog_unix.go create mode 100644 vendor/src/github.com/RackSec/srslog/writer.go diff --git a/hack/vendor.sh b/hack/vendor.sh index 32356d8be3..6d6bee3b1a 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -23,6 +23,7 @@ clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://gith clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3 clone git github.com/docker/go-connections v0.1.2 clone git github.com/docker/engine-api v0.1.3 +clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de #get libnetwork packages clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436 diff --git a/vendor/src/github.com/RackSec/srslog/.gitignore b/vendor/src/github.com/RackSec/srslog/.gitignore new file mode 100644 index 0000000000..ebf0f2e4e3 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/.gitignore @@ -0,0 +1 @@ +.cover diff --git a/vendor/src/github.com/RackSec/srslog/.travis.yml b/vendor/src/github.com/RackSec/srslog/.travis.yml new file mode 100644 index 0000000000..767c1d811e --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/.travis.yml @@ -0,0 +1,13 @@ +sudo: required +dist: trusty +group: edge +language: go +go: +- 1.5 +script: +- | + go get ./... + go test -v ./... +notifications: + slack: + secure: dtDue9gP6CRR1jYjEf6raXXFak3QKGcCFvCf5mfvv5XScdpmc3udwgqc5TdyjC0goaC9OK/4jTcCD30dYZm/u6ux3E9mo3xwMl2xRLHx76p5r9rSQtloH19BDwA2+A+bpDfFQVz05k2YXuTiGSvNMMdwzx+Dr294Sl/z43RFB4+b9/R/6LlFpRW89IwftvpLAFnBy4K/ZcspQzKM+rQfQTL5Kk+iZ/KBsuR/VziDq6MoJ8t43i4ee8vwS06vFBKDbUiZ4FIZpLgc2RAL5qso5aWRKYXL6waXfoKHZWKPe0w4+9IY1rDJxG1jEb7YGgcbLaF9xzPRRs2b2yO/c87FKpkh6PDgYHfLjpgXotCoojZrL4p1x6MI1ldJr3NhARGPxS9r4liB9n6Y5nD+ErXi1IMf55fuUHcPY27Jc0ySeLFeM6cIWJ8OhFejCgGw6a5DnnmJo0PqopsaBDHhadpLejT1+K6bL2iGkT4SLcVNuRGLs+VyuNf1+5XpkWZvy32vquO7SZOngLLBv+GIem+t3fWm0Z9s/0i1uRCQei1iUutlYjoV/LBd35H2rhob4B5phIuJin9kb0zbHf6HnaoN0CtN8r0d8G5CZiInVlG5Xcid5Byb4dddf5U2EJTDuCMVyyiM7tcnfjqw9UbVYNxtYM9SzcqIq+uVqM8pYL9xSec= diff --git a/vendor/src/github.com/RackSec/srslog/CODE_OF_CONDUCT.md b/vendor/src/github.com/RackSec/srslog/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..18ac49fc75 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/CODE_OF_CONDUCT.md @@ -0,0 +1,50 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating +documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to +fairly and consistently applying these principles to every aspect of managing +this project. Project maintainers who do not follow or enforce the Code of +Conduct may be permanently removed from the project team. + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting a project maintainer at [sirsean@gmail.com]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. Maintainers are +obligated to maintain confidentiality with regard to the reporter of an +incident. + + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.3.0, available at +[http://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/3/0/ diff --git a/vendor/src/github.com/RackSec/srslog/LICENSE b/vendor/src/github.com/RackSec/srslog/LICENSE new file mode 100644 index 0000000000..9269338fbb --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2015 Rackspace. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/src/github.com/RackSec/srslog/README.md b/vendor/src/github.com/RackSec/srslog/README.md new file mode 100644 index 0000000000..1ae1fd4ef8 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/README.md @@ -0,0 +1,131 @@ +[![Build Status](https://travis-ci.org/RackSec/srslog.svg?branch=master)](https://travis-ci.org/RackSec/srslog) + +# srslog + +Go has a `syslog` package in the standard library, but it has the following +shortcomings: + +1. It doesn't have TLS support +2. [According to bradfitz on the Go team, it is no longer being maintained.](https://github.com/golang/go/issues/13449#issuecomment-161204716) + +I agree that it doesn't need to be in the standard library. So, I've +followed Brad's suggestion and have made a separate project to handle syslog. + +This code was taken directly from the Go project as a base to start from. + +However, this _does_ have TLS support. + +# Usage + +Basic usage retains the same interface as the original `syslog` package. We +only added to the interface where required to support new functionality. + +Switch from the standard library: + +``` +import( + //"log/syslog" + syslog "github.com/RackSec/srslog" +) +``` + +You can still use it for local syslog: + +``` +w, err := syslog.Dial("", "", syslog.LOG_ERR, "testtag") +``` + +Or to unencrypted UDP: + +``` +w, err := syslog.Dial("udp", "192.168.0.50:514", syslog.LOG_ERR, "testtag") +``` + +Or to unencrypted TCP: + +``` +w, err := syslog.Dial("tcp", "192.168.0.51:514", syslog.LOG_ERR, "testtag") +``` + +But now you can also send messages via TLS-encrypted TCP: + +``` +w, err := syslog.DialWithTLSCertPath("tcp+tls", "192.168.0.52:514", syslog.LOG_ERR, "testtag", "/path/to/servercert.pem") +``` + +And if you need more control over your TLS configuration : + +``` +pool := x509.NewCertPool() +serverCert, err := ioutil.ReadFile("/path/to/servercert.pem") +if err != nil { + return nil, err +} +pool.AppendCertsFromPEM(serverCert) +config := tls.Config{ + RootCAs: pool, +} + +w, err := DialWithTLSConfig(network, raddr, priority, tag, &config) +``` + +(Note that in both TLS cases, this uses a self-signed certificate, where the +remote syslog server has the keypair and the client has only the public key.) + +And then to write log messages, continue like so: + +``` +if err != nil { + log.Fatal("failed to connect to syslog:", err) +} +defer w.Close() + +w.Alert("this is an alert") +w.Crit("this is critical") +w.Err("this is an error") +w.Warning("this is a warning") +w.Notice("this is a notice") +w.Info("this is info") +w.Debug("this is debug") +w.Write([]byte("these are some bytes")) +``` + +# Generating TLS Certificates + +We've provided a script that you can use to generate a self-signed keypair: + +``` +pip install cryptography +python script/gen-certs.py +``` + +That outputs the public key and private key to standard out. Put those into +`.pem` files. (And don't put them into any source control. The certificate in +the `test` directory is used by the unit tests, and please do not actually use +it anywhere else.) + +# Running Tests + +Run the tests as usual: + +``` +go test +``` + +But we've also provided a test coverage script that will show you which +lines of code are not covered: + +``` +script/coverage --html +``` + +That will open a new browser tab showing coverage information. + +# License + +This project uses the New BSD License, the same as the Go project itself. + +# Code of Conduct + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. diff --git a/vendor/src/github.com/RackSec/srslog/constants.go b/vendor/src/github.com/RackSec/srslog/constants.go new file mode 100644 index 0000000000..600801ee84 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/constants.go @@ -0,0 +1,68 @@ +package srslog + +import ( + "errors" +) + +// Priority is a combination of the syslog facility and +// severity. For example, LOG_ALERT | LOG_FTP sends an alert severity +// message from the FTP facility. The default severity is LOG_EMERG; +// the default facility is LOG_KERN. +type Priority int + +const severityMask = 0x07 +const facilityMask = 0xf8 + +const ( + // Severity. + + // From /usr/include/sys/syslog.h. + // These are the same on Linux, BSD, and OS X. + LOG_EMERG Priority = iota + LOG_ALERT + LOG_CRIT + LOG_ERR + LOG_WARNING + LOG_NOTICE + LOG_INFO + LOG_DEBUG +) + +const ( + // Facility. + + // From /usr/include/sys/syslog.h. + // These are the same up to LOG_FTP on Linux, BSD, and OS X. + LOG_KERN Priority = iota << 3 + LOG_USER + LOG_MAIL + LOG_DAEMON + LOG_AUTH + LOG_SYSLOG + LOG_LPR + LOG_NEWS + LOG_UUCP + LOG_CRON + LOG_AUTHPRIV + LOG_FTP + _ // unused + _ // unused + _ // unused + _ // unused + LOG_LOCAL0 + LOG_LOCAL1 + LOG_LOCAL2 + LOG_LOCAL3 + LOG_LOCAL4 + LOG_LOCAL5 + LOG_LOCAL6 + LOG_LOCAL7 +) + +func validatePriority(p Priority) error { + if p < 0 || p > LOG_LOCAL7|LOG_DEBUG { + return errors.New("log/syslog: invalid priority") + } else { + return nil + } +} diff --git a/vendor/src/github.com/RackSec/srslog/dialer.go b/vendor/src/github.com/RackSec/srslog/dialer.go new file mode 100644 index 0000000000..7811538943 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/dialer.go @@ -0,0 +1,53 @@ +package srslog + +import ( + "crypto/tls" + "net" +) + +func (w Writer) getDialer() func() (serverConn, string, error) { + dialers := map[string]func() (serverConn, string, error){ + "": w.unixDialer, + "tcp+tls": w.tlsDialer, + } + dialer, ok := dialers[w.network] + if !ok { + dialer = w.basicDialer + } + return dialer +} + +func (w Writer) unixDialer() (serverConn, string, error) { + sc, err := unixSyslog() + hostname := w.hostname + if hostname == "" { + hostname = "localhost" + } + return sc, hostname, err +} + +func (w Writer) tlsDialer() (serverConn, string, error) { + c, err := tls.Dial("tcp", w.raddr, w.tlsConfig) + var sc serverConn + hostname := w.hostname + if err == nil { + sc = &netConn{conn: c} + if hostname == "" { + hostname = c.LocalAddr().String() + } + } + return sc, hostname, err +} + +func (w Writer) basicDialer() (serverConn, string, error) { + c, err := net.Dial(w.network, w.raddr) + var sc serverConn + hostname := w.hostname + if err == nil { + sc = &netConn{conn: c} + if hostname == "" { + hostname = c.LocalAddr().String() + } + } + return sc, hostname, err +} diff --git a/vendor/src/github.com/RackSec/srslog/net_conn.go b/vendor/src/github.com/RackSec/srslog/net_conn.go new file mode 100644 index 0000000000..a73394c69c --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/net_conn.go @@ -0,0 +1,24 @@ +package srslog + +import ( + "fmt" + "net" + "os" + "time" +) + +type netConn struct { + conn net.Conn +} + +func (n *netConn) writeString(p Priority, hostname, tag, msg string) error { + timestamp := time.Now().Format(time.RFC3339) + _, err := fmt.Fprintf(n.conn, "<%d>%s %s %s[%d]: %s", + p, timestamp, hostname, + tag, os.Getpid(), msg) + return err +} + +func (n *netConn) close() error { + return n.conn.Close() +} diff --git a/vendor/src/github.com/RackSec/srslog/srslog.go b/vendor/src/github.com/RackSec/srslog/srslog.go new file mode 100644 index 0000000000..3d03272d56 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/srslog.go @@ -0,0 +1,96 @@ +package srslog + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + "log" + "os" +) + +// This interface and the separate syslog_unix.go file exist for +// Solaris support as implemented by gccgo. On Solaris you can not +// simply open a TCP connection to the syslog daemon. The gccgo +// sources have a syslog_solaris.go file that implements unixSyslog to +// return a type that satisfies this interface and simply calls the C +// library syslog function. +type serverConn interface { + writeString(p Priority, hostname, tag, s string) error + close() error +} + +// New establishes a new connection to the system log daemon. Each +// write to the returned Writer sends a log message with the given +// priority and prefix. +func New(priority Priority, tag string) (w *Writer, err error) { + return Dial("", "", priority, tag) +} + +// Dial establishes a connection to a log daemon by connecting to +// address raddr on the specified network. Each write to the returned +// Writer sends a log message with the given facility, severity and +// tag. +// If network is empty, Dial will connect to the local syslog server. +func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) { + return DialWithTLSConfig(network, raddr, priority, tag, nil) +} + +// DialWithTLSCertPath establishes a secure connection to a log daemon by connecting to +// address raddr on the specified network. It uses certPath to load TLS certificates and configure +// the secure connection. +func DialWithTLSCertPath(network, raddr string, priority Priority, tag, certPath string) (*Writer, error) { + pool := x509.NewCertPool() + serverCert, err := ioutil.ReadFile(certPath) + if err != nil { + return nil, err + } + pool.AppendCertsFromPEM(serverCert) + config := tls.Config{ + RootCAs: pool, + } + + return DialWithTLSConfig(network, raddr, priority, tag, &config) +} + +// DialWithTLSConfig establishes a secure connection to a log daemon by connecting to +// address raddr on the specified network. It uses tlsConfig to configure the secure connection. +func DialWithTLSConfig(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config) (*Writer, error) { + if err := validatePriority(priority); err != nil { + return nil, err + } + + if tag == "" { + tag = os.Args[0] + } + hostname, _ := os.Hostname() + + w := &Writer{ + priority: priority, + tag: tag, + hostname: hostname, + network: network, + raddr: raddr, + tlsConfig: tlsConfig, + } + + w.Lock() + defer w.Unlock() + + err := w.connect() + if err != nil { + return nil, err + } + return w, err +} + +// NewLogger creates a log.Logger whose output is written to +// the system log service with the specified priority. The logFlag +// argument is the flag set passed through to log.New to create +// the Logger. +func NewLogger(p Priority, logFlag int) (*log.Logger, error) { + s, err := New(p, "") + if err != nil { + return nil, err + } + return log.New(s, "", logFlag), nil +} diff --git a/vendor/src/github.com/RackSec/srslog/srslog_unix.go b/vendor/src/github.com/RackSec/srslog/srslog_unix.go new file mode 100644 index 0000000000..430065c738 --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/srslog_unix.go @@ -0,0 +1,47 @@ +package srslog + +import ( + "errors" + "fmt" + "net" + "os" + "time" +) + +// unixSyslog opens a connection to the syslog daemon running on the +// local machine using a Unix domain socket. + +func unixSyslog() (conn serverConn, err error) { + logTypes := []string{"unixgram", "unix"} + logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"} + for _, network := range logTypes { + for _, path := range logPaths { + conn, err := net.Dial(network, path) + if err != nil { + continue + } else { + return &localConn{conn: conn}, nil + } + } + } + return nil, errors.New("Unix syslog delivery error") +} + +type localConn struct { + conn net.Conn +} + +func (n *localConn) writeString(p Priority, hostname, tag, msg string) error { + // Compared to the network form at srslog.netConn, the changes are: + // 1. Use time.Stamp instead of time.RFC3339. + // 2. Drop the hostname field from the Fprintf. + timestamp := time.Now().Format(time.Stamp) + _, err := fmt.Fprintf(n.conn, "<%d>%s %s[%d]: %s", + p, timestamp, + tag, os.Getpid(), msg) + return err +} + +func (n *localConn) close() error { + return n.conn.Close() +} diff --git a/vendor/src/github.com/RackSec/srslog/writer.go b/vendor/src/github.com/RackSec/srslog/writer.go new file mode 100644 index 0000000000..1e7e2ebbdb --- /dev/null +++ b/vendor/src/github.com/RackSec/srslog/writer.go @@ -0,0 +1,152 @@ +package srslog + +import ( + "crypto/tls" + "strings" + "sync" +) + +// A Writer is a connection to a syslog server. +type Writer struct { + sync.Mutex // guards conn + + priority Priority + tag string + hostname string + network string + raddr string + tlsConfig *tls.Config + + conn serverConn +} + +// connect makes a connection to the syslog server. +// It must be called with w.mu held. +func (w *Writer) connect() (err error) { + if w.conn != nil { + // ignore err from close, it makes sense to continue anyway + w.conn.close() + w.conn = nil + } + + var conn serverConn + var hostname string + dialer := w.getDialer() + conn, hostname, err = dialer() + if err == nil { + w.conn = conn + w.hostname = hostname + } + + return +} + +// Write sends a log message to the syslog daemon using the default priority +// passed into `srslog.New` or the `srslog.Dial*` functions. +func (w *Writer) Write(b []byte) (int, error) { + return w.writeAndRetry(w.priority, string(b)) +} + +// Close closes a connection to the syslog daemon. +func (w *Writer) Close() error { + w.Lock() + defer w.Unlock() + + if w.conn != nil { + err := w.conn.close() + w.conn = nil + return err + } + return nil +} + +// Emerg logs a message with severity LOG_EMERG; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Emerg(m string) (err error) { + _, err = w.writeAndRetry(LOG_EMERG, m) + return err +} + +// Alert logs a message with severity LOG_ALERT; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Alert(m string) (err error) { + _, err = w.writeAndRetry(LOG_ALERT, m) + return err +} + +// Crit logs a message with severity LOG_CRIT; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Crit(m string) (err error) { + _, err = w.writeAndRetry(LOG_CRIT, m) + return err +} + +// Err logs a message with severity LOG_ERR; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Err(m string) (err error) { + _, err = w.writeAndRetry(LOG_ERR, m) + return err +} + +// Warning logs a message with severity LOG_WARNING; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Warning(m string) (err error) { + _, err = w.writeAndRetry(LOG_WARNING, m) + return err +} + +// Notice logs a message with severity LOG_NOTICE; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Notice(m string) (err error) { + _, err = w.writeAndRetry(LOG_NOTICE, m) + return err +} + +// Info logs a message with severity LOG_INFO; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Info(m string) (err error) { + _, err = w.writeAndRetry(LOG_INFO, m) + return err +} + +// Debug logs a message with severity LOG_DEBUG; this overrides the default +// priority passed to `srslog.New` and the `srslog.Dial*` functions. +func (w *Writer) Debug(m string) (err error) { + _, err = w.writeAndRetry(LOG_DEBUG, m) + return err +} + +func (w *Writer) writeAndRetry(p Priority, s string) (int, error) { + pr := (w.priority & facilityMask) | (p & severityMask) + + w.Lock() + defer w.Unlock() + + if w.conn != nil { + if n, err := w.write(pr, s); err == nil { + return n, err + } + } + if err := w.connect(); err != nil { + return 0, err + } + return w.write(pr, s) +} + +// write generates and writes a syslog formatted string. The +// format is as follows: TIMESTAMP HOSTNAME TAG[PID]: MSG +func (w *Writer) write(p Priority, msg string) (int, error) { + // ensure it ends in a \n + if !strings.HasSuffix(msg, "\n") { + msg += "\n" + } + + err := w.conn.writeString(p, w.hostname, w.tag, msg) + if err != nil { + return 0, err + } + // Note: return the length of the input, not the number of + // bytes printed by Fprintf, because this must behave like + // an io.Writer. + return len(msg), nil +} From 4b98193beab00bc6cf48762858570a1bd418c9ef Mon Sep 17 00:00:00 2001 From: David Calavera Date: Fri, 8 Jan 2016 12:36:31 -0500 Subject: [PATCH 2/2] Add support for syslog over TLS. Signed-off-by: David Calavera --- daemon/logger/syslog/syslog.go | 46 ++++++++++++++++++++++++------ docs/reference/logging/overview.md | 19 +++++++++++- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/daemon/logger/syslog/syslog.go b/daemon/logger/syslog/syslog.go index 7d052a662f..f6861947a6 100644 --- a/daemon/logger/syslog/syslog.go +++ b/daemon/logger/syslog/syslog.go @@ -4,9 +4,9 @@ package syslog import ( + "crypto/tls" "errors" "fmt" - "log/syslog" "net" "net/url" "os" @@ -14,13 +14,19 @@ import ( "strconv" "strings" + syslog "github.com/RackSec/srslog" + "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger/loggerutils" "github.com/docker/docker/pkg/urlutil" + "github.com/docker/go-connections/tlsconfig" ) -const name = "syslog" +const ( + name = "syslog" + secureProto = "tcp+tls" +) var facilities = map[string]syslog.Priority{ "kern": syslog.LOG_KERN, @@ -77,12 +83,19 @@ func New(ctx logger.Context) (logger.Logger, error) { return nil, err } - log, err := syslog.Dial( - proto, - address, - facility, - path.Base(os.Args[0])+"/"+tag, - ) + logTag := path.Base(os.Args[0]) + "/" + tag + + var log *syslog.Writer + if proto == secureProto { + tlsConfig, tlsErr := parseTLSConfig(ctx.Config) + if tlsErr != nil { + return nil, tlsErr + } + log, err = syslog.DialWithTLSConfig(proto, address, facility, logTag, tlsConfig) + } else { + log, err = syslog.Dial(proto, address, facility, logTag) + } + if err != nil { return nil, err } @@ -147,6 +160,10 @@ func ValidateLogOpt(cfg map[string]string) error { case "syslog-address": case "syslog-facility": case "syslog-tag": + case "syslog-tls-ca-cert": + case "syslog-tls-cert": + case "syslog-tls-key": + case "syslog-tls-skip-verify": case "tag": default: return fmt.Errorf("unknown log opt '%s' for syslog log driver", key) @@ -177,3 +194,16 @@ func parseFacility(facility string) (syslog.Priority, error) { return syslog.Priority(0), errors.New("invalid syslog facility") } + +func parseTLSConfig(cfg map[string]string) (*tls.Config, error) { + _, skipVerify := cfg["syslog-tls-skip-verify"] + + opts := tlsconfig.Options{ + CAFile: cfg["syslog-tls-ca-cert"], + CertFile: cfg["syslog-tls-cert"], + KeyFile: cfg["syslog-tls-key"], + InsecureSkipVerify: skipVerify, + } + + return tlsconfig.Client(opts) +} diff --git a/docs/reference/logging/overview.md b/docs/reference/logging/overview.md index 8d91b0d1ad..4ef937b558 100644 --- a/docs/reference/logging/overview.md +++ b/docs/reference/logging/overview.md @@ -69,9 +69,13 @@ If `max-size` and `max-file` are set, `docker logs` only returns the log lines f The following logging options are supported for the `syslog` logging driver: - --log-opt syslog-address=[tcp|udp]://host:port + --log-opt syslog-address=[tcp|udp|tcp+tls]://host:port --log-opt syslog-address=unix://path --log-opt syslog-facility=daemon + --log-opt syslog-tls-ca-cert=/etc/ca-certificates/custom/ca.pem + --log-opt syslog-tls-cert=/etc/ca-certificates/custom/cert.pem + --log-opt syslog-tls-key=/etc/ca-certificates/custom/key.pem + --log-opt syslog-tls-skip-verify=true --log-opt tag="mailer" `syslog-address` specifies the remote syslog server address where the driver connects to. @@ -107,6 +111,19 @@ the following named facilities: * `local6` * `local7` +`syslog-tls-ca-cert` specifies the absolute path to the trust certificates +signed by the CA. This option is ignored if the address protocol is not `tcp+tls`. + +`syslog-tls-cert` specifies the absolute path to the TLS certificate file. +This option is ignored if the address protocol is not `tcp+tls`. + +`syslog-tls-key` specifies the absolute path to the TLS key file. +This option is ignored if the address protocol is not `tcp+tls`. + +`syslog-tls-skip-verify` configures the TLS verification. +This verification is enabled by default, but it can be overriden by setting +this option to `true`. This option is ignored if the address protocol is not `tcp+tls`. + By default, Docker uses the first 12 characters of the container ID to tag log messages. Refer to the [log tag option documentation](log_tags.md) for customizing the log tag format.