Added micromdm/go4 as a dependency. (#229)

Improves http debug logging by also logging the sent response.
Converts regular http logs to key-value format.
Changes the http server options to httputil.ListenAndServe, which is antended to be a standard
ListenAndServe method for all micromdm project.

Adds environment variables as configuration options for sensitive values.
Closes #196
This commit is contained in:
Victor Vrantchan
2017-09-11 17:14:12 +03:00
committed by GitHub
parent 07adb497bb
commit fe191eb7cc
7 changed files with 103 additions and 230 deletions

View File

@@ -1,3 +1,8 @@
# TBD
* Added ENV variables for sensitive flags: `MICROMDM_APNS_KEY_PASSWORD`,`MICROMDM_API_KEY`
* Removed the `-redir-addr` flag. Redirect to HTTPS is only enabled when the 443 port is used.
# v1.1.0 June 05 2017
* Import and sign pkgs, generate appmanifest on import.

46
Gopkg.lock generated
View File

@@ -10,8 +10,8 @@
[[projects]]
name = "github.com/boltdb/bolt"
packages = ["."]
revision = "583e8937c61f1af6513608ccc75c97b6abdf4ff9"
version = "v1.3.0"
revision = "2f1ce7a837dcb8da3ec595b1dac9d0632f0f99e8"
version = "v1.3.1"
[[projects]]
branch = "master"
@@ -23,11 +23,11 @@
branch = "master"
name = "github.com/garyburd/go-oauth"
packages = ["oauth"]
revision = "d9dbc37b1a7acf4923050e614fc7861e3fbf42f9"
revision = "166ce8d672783fbb5a72247c3cf459267717e1ec"
[[projects]]
name = "github.com/go-kit/kit"
packages = ["endpoint","log","metrics","transport/http"]
packages = ["endpoint","log","log/level","metrics","transport/http"]
revision = "fadad6fffe0466b19df9efd9acde5c9a52df5fa4"
version = "v0.4.0"
@@ -40,8 +40,8 @@
[[projects]]
name = "github.com/go-stack/stack"
packages = ["."]
revision = "7a2f19628aabfe68f0766b59e74d6315f8347d22"
version = "v1.5.3"
revision = "817915b46b97fd7bb80e8ab6b69f01a53ac3eebf"
version = "v1.6.0"
[[projects]]
name = "github.com/gogo/protobuf"
@@ -53,7 +53,7 @@
branch = "master"
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "e325f446bebc2998605911c0a2650d9920361d4a"
revision = "17ce1425424ab154092bbb43af630bd647f3bb0d"
[[projects]]
name = "github.com/gorilla/context"
@@ -61,18 +61,18 @@
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
version = "v1.1"
[[projects]]
name = "github.com/gorilla/handlers"
packages = ["."]
revision = "a4043c62cc2329bacda331d33fc908ab11ef0ec3"
version = "v1.2.1"
[[projects]]
name = "github.com/gorilla/mux"
packages = ["."]
revision = "bcd8bc72b08df0f70df986b97f95590779502d31"
version = "v1.4.0"
[[projects]]
branch = "master"
name = "github.com/groob/finalizer"
packages = [".","logutil"]
revision = "4c2ed49aabdaa038f247d72d183e410757cdbe9c"
[[projects]]
branch = "master"
name = "github.com/groob/plist"
@@ -91,11 +91,17 @@
packages = ["."]
revision = "3e565f89e59266df10c92da54118bf13ec312905"
[[projects]]
branch = "master"
name = "github.com/micromdm/go4"
packages = ["httputil","version"]
revision = "486ea5f130c78a9c058374eb159df08296caea9d"
[[projects]]
branch = "master"
name = "github.com/micromdm/mdm"
packages = ["."]
revision = "1b8ad711b42f5510344c657a195d7eede8479728"
revision = "97c19c7edf3498cf43b378042317d9d9caa84dc6"
[[projects]]
name = "github.com/micromdm/scep"
@@ -119,35 +125,35 @@
branch = "master"
name = "golang.org/x/crypto"
packages = ["acme","acme/autocert","pkcs12","pkcs12/internal/rc2"]
revision = "850760c427c516be930bc91280636328f1a62286"
revision = "9ba3862cf6a5452ae579de98f9364dd2e544844c"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["context","context/ctxhttp","http2","http2/hpack","idna","lex/httplex"]
revision = "dfe83d419c9403b40b19d08cdba2afec27b002f7"
revision = "66aacef3dd8a676686c7ae3716979581e8b03c47"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "0b25a408a50076fbbcae6b7ac0ea5fbb0b085e79"
revision = "a5054c7c1385fd50d9394475365355a87a7873ec"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = ["internal/gen","internal/triegen","internal/ucd","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
revision = "3491b61b9edc56653ad4333e605e2908e46a036b"
revision = "bd91bbf73e9a4a801adbfb97133c992678533126"
[[projects]]
branch = "master"
name = "golang.org/x/tools"
packages = ["go/ast/astutil","imports"]
revision = "b4e0c5ecfb3125b1fbb235b1d381898d2b2a16d6"
revision = "3b1faeda9afbcba128c2d794b38ffe7982141139"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "9502148927d630aed51089b18e46395f56995ed144a986d44a960379d1bff4b8"
inputs-digest = "6ef27b152096e36c87702ca8c72c8fe0121399d323dc59d8b539dd4bc3ba4e9a"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -18,13 +18,13 @@ SHELL = /bin/bash
BUILD_VERSION = "\
-X github.com/micromdm/micromdm/version.appName=${APP_NAME} \
-X github.com/micromdm/micromdm/version.version=${VERSION} \
-X github.com/micromdm/micromdm/version.branch=${BRANCH} \
-X github.com/micromdm/micromdm/version.buildUser=${USER} \
-X github.com/micromdm/micromdm/version.buildDate=${NOW} \
-X github.com/micromdm/micromdm/version.revision=${REVISION} \
-X github.com/micromdm/micromdm/version.goVersion=${GOVERSION}"
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.appName=${APP_NAME} \
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.version=${VERSION} \
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.branch=${BRANCH} \
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.buildUser=${USER} \
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.buildDate=${NOW} \
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.revision=${REVISION} \
-X github.com/micromdm/micromdm/vendor/github.com/micromdm/go4/version.goVersion=${GOVERSION}"
WORKSPACE = ${GOPATH}/src/github.com/micromdm/micromdm
check-deps:
@@ -63,21 +63,27 @@ INSTALL_STEPS := \
install-local: $(INSTALL_STEPS)
APP_NAME = mdmctl
mdmctl: .pre-build
.pre-mdmctl:
$(eval APP_NAME = mdmctl)
mdmctl: .pre-build .pre-mdmctl
go build -i -o build/darwin/mdmctl -ldflags ${BUILD_VERSION} ./cmd/mdmctl
install-mdmctl:
install-mdmctl: .pre-mdmctl
go install -ldflags ${BUILD_VERSION} ./cmd/mdmctl
APP_NAME = micromdm
micromdm: .pre-build
.pre-micromdm:
$(eval APP_NAME = micromdm)
micromdm: .pre-build .pre-micromdm
go build -i -o build/darwin/micromdm -ldflags ${BUILD_VERSION} ./cmd/mdmctl
install-micromdm:
install-micromdm: .pre-micromdm
go install -ldflags ${BUILD_VERSION}
xp-micromdm: .pre-build
xp-micromdm: .pre-build .pre-micromdm
GOOS=darwin go build -i -o build/darwin/micromdm -ldflags ${BUILD_VERSION}
GOOS=linux CGO_ENABLED=0 go build -i -o build/linux/micromdm -ldflags ${BUILD_VERSION}

View File

@@ -7,7 +7,7 @@ import (
"strings"
"text/tabwriter"
"github.com/micromdm/micromdm/version"
"github.com/micromdm/go4/version"
)
func main() {

View File

@@ -9,7 +9,7 @@ import (
"text/tabwriter"
"time"
"github.com/micromdm/micromdm/version"
"github.com/micromdm/go4/version"
)
func init() {

177
serve.go
View File

@@ -14,16 +14,14 @@ import (
"io/ioutil"
stdlog "log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/fullsailor/pkcs7"
"github.com/groob/finalizer/logutil"
"github.com/micromdm/go4/env"
"golang.org/x/crypto/acme/autocert"
"golang.org/x/crypto/pkcs12"
@@ -32,11 +30,11 @@ import (
"github.com/go-kit/kit/endpoint"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/micromdm/dep"
"github.com/micromdm/go4/httputil"
boltdepot "github.com/micromdm/scep/depot/bolt"
scep "github.com/micromdm/scep/server"
@@ -84,15 +82,14 @@ func serve(args []string) error {
var (
flConfigPath = flagset.String("config-path", "/var/db/micromdm", "path to configuration directory")
flServerURL = flagset.String("server-url", "", "public HTTPS url of your server")
flAPIKey = flagset.String("api-key", "", "API Token for mdmctl command")
flAPIKey = flagset.String("api-key", env.String("MICROMDM_API_KEY", ""), "API Token for mdmctl command")
flAPNSCertPath = flagset.String("apns-cert", "", "path to APNS certificate")
flAPNSKeyPass = flagset.String("apns-password", "", "password for your p12 APNS cert file (if using)")
flAPNSKeyPass = flagset.String("apns-password", env.String("MICROMDM_APNS_KEY_PASSWORD", ""), "password for your p12 APNS cert file (if using)")
flAPNSKeyPath = flagset.String("apns-key", "", "path to key file if using .pem push cert")
flTLS = flagset.Bool("tls", true, "use https")
flTLSCert = flagset.String("tls-cert", "", "path to TLS certificate")
flTLSKey = flagset.String("tls-key", "", "path to TLS private key")
flHTTPAddr = flagset.String("http-addr", ":https", "http(s) listen address of mdm server. defaults to :8080 if tls is false")
flRedirAddr = flagset.String("redir-addr", ":http", "http redirect to https listen address")
flHTTPDebug = flagset.Bool("http-debug", false, "enable debug for http(dumps full request)")
flRepoPath = flagset.String("filerepo", "", "path to http file repo")
flDepSim = flagset.Bool("depsim", false, "use depsim config")
@@ -348,67 +345,61 @@ func serve(args []string) error {
var handler http.Handler
if *flHTTPDebug {
handler = debugHTTPmiddleware(r)
handler = httputil.HTTPDebugMiddleware(os.Stdout, true, logger.Log)(r)
} else {
handler = r
}
handler = handlers.CombinedLoggingHandler(os.Stdout, handler)
srv := &http.Server{
Addr: *flHTTPAddr,
Handler: handler,
ReadTimeout: 60 * time.Second,
WriteTimeout: 60 * time.Second,
ReadHeaderTimeout: 10 * time.Second,
IdleTimeout: 10 * time.Minute,
MaxHeaderBytes: 1 << 18, // 0.25 MB
TLSConfig: tlsConfig(),
}
handler = logutil.NewHTTPLogger(httpLogger).Middleware(handler)
srvURL, err := url.Parse(sm.ServerPublicURL)
if err != nil {
stdlog.Fatal(err)
return errors.Wrapf(err, "parsing serverURL %q", sm.ServerPublicURL)
}
errs := make(chan error, 2)
go func() {
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig // block on signal then gracefully shutdown.
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
errs <- srv.Shutdown(ctx)
}()
serveOpts := serveOptions(
handler,
*flHTTPAddr,
srvURL.Hostname(),
logger,
*flTLSCert,
*flTLSKey,
sm.configPath,
*flTLS,
)
err = httputil.ListenAndServe(serveOpts...)
return errors.Wrap(err, "calling ListenAndServe")
}
go func() {
logger := log.With(logger, "transport", "HTTP")
if !*flTLS {
var httpAddr string
if *flHTTPAddr == ":https" {
httpAddr = ":8080"
} else {
httpAddr = *flHTTPAddr
}
logger.Log("addr", httpAddr)
errs <- http.ListenAndServe(httpAddr, handler)
return
}
tlsFromFile := (*flTLSCert != "" && *flTLSKey != "")
if tlsFromFile {
logger.Log("addr", srv.Addr)
redirectTLS(*flRedirAddr, sm.ServerPublicURL)
errs <- serveTLS(srv, *flTLSCert, *flTLSKey)
return
} else {
logger.Log("addr", srv.Addr)
redirectTLS(*flRedirAddr, sm.ServerPublicURL)
errs <- serveACME(srv, srvURL.Hostname(), filepath.Join(sm.configPath, "le-certificates"))
return
}
}()
mainLogger.Log("terminated", <-errs)
return nil
// serveOptions configures the []httputil.Options for ListenAndServe
func serveOptions(
handler http.Handler,
addr string,
hostname string,
logger log.Logger,
certPath string,
keyPath string,
configPath string,
tls bool,
) []httputil.Option {
tlsFromFile := (certPath != "" && keyPath != "")
serveOpts := []httputil.Option{
httputil.WithACMEHosts([]string{hostname}),
httputil.WithLogger(logger),
httputil.WithHTTPHandler(handler),
}
if tlsFromFile {
serveOpts = append(serveOpts, httputil.WithKeyPair(certPath, keyPath))
}
if !tls && addr == ":https" {
serveOpts = append(serveOpts, httputil.WithAddress(":8080"))
}
if tls {
serveOpts = append(serveOpts, httputil.WithAutocertCache(autocert.DirCache(filepath.Join(configPath, "le-certificates"))))
}
if addr != ":https" {
serveOpts = append(serveOpts, httputil.WithAddress(addr))
}
return serveOpts
}
func printExamples() {
@@ -424,57 +415,6 @@ func printExamples() {
fmt.Println(exampleText)
}
func serveTLS(server *http.Server, certPath, keyPath string) error {
err := server.ListenAndServeTLS(certPath, keyPath)
return err
}
func serveACME(server *http.Server, domain, cachePath string) error {
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(domain),
Cache: autocert.DirCache(cachePath),
}
server.TLSConfig.GetCertificate = m.GetCertificate
err := server.ListenAndServeTLS("", "")
return err
}
// redirects port 80 to port 443
func redirectTLS(addr, serverUrl string) {
srv := &http.Server{
Addr: addr,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Connection", "close")
url := serverUrl + req.URL.String()
http.Redirect(w, req, url, http.StatusMovedPermanently)
}),
}
go func() { stdlog.Fatal(srv.ListenAndServe()) }()
}
func tlsConfig() *tls.Config {
cfg := &tls.Config{
PreferServerCipherSuites: true,
CurvePreferences: []tls.CurveID{
tls.CurveP256,
tls.X25519,
},
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
}
return cfg
}
type config struct {
configPath string
depsim bool
@@ -792,21 +732,6 @@ func (c *config) setupSCEP(logger log.Logger) {
}
}
func debugHTTPmiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body := io.TeeReader(r.Body, os.Stderr)
r.Body = ioutil.NopCloser(body)
out, err := httputil.DumpRequest(r, true)
if err != nil {
stdlog.Println(err)
}
fmt.Println("")
fmt.Println(string(out))
fmt.Println("")
next.ServeHTTP(w, r)
})
}
// TODO: move to separate package/library
func mdmAuthSignMessageMiddleware(db *boltdepot.Depot, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,69 +0,0 @@
// Package version provides utilities for displaying version information.
package version
import (
"encoding/json"
"fmt"
"net/http"
)
// go build -ldflags "-X github.com/micromdm/micromdm/version.version=1.0.0"
var (
version = "unknown"
branch = "unknown"
revision = "unknown"
goVersion = "unknown"
buildDate = "unknown"
buildUser = "unknown"
appName = "micromdm"
)
// Info holds version and build info about the app.
type Info struct {
Version string `json:"version"`
Branch string `json:"branch"`
Revision string `json:"revision"`
GoVersion string `json:"go_version"`
BuildDate string `json:"build_date"`
BuildUser string `json:"build_user"`
}
// Version returns a struct with the current version information.
func Version() Info {
return Info{
Version: version,
Branch: branch,
Revision: revision,
GoVersion: goVersion,
BuildDate: buildDate,
BuildUser: buildUser,
}
}
// Print outputs the app name and version string.
func Print() {
v := Version()
fmt.Printf("%s version %s\n", appName, v.Version)
}
// PrintFull outputs the app name and detailed version information.
func PrintFull() {
v := Version()
fmt.Printf("%s - version %s\n", appName, v.Version)
fmt.Printf(" branch: \t%s\n", v.Branch)
fmt.Printf(" revision: \t%s\n", v.Revision)
fmt.Printf(" build date: \t%s\n", v.BuildDate)
fmt.Printf(" build user: \t%s\n", v.BuildUser)
fmt.Printf(" go version: \t%s\n", v.GoVersion)
}
// Handler provides an HTTP Handler which returns JSON formatted version info.
func Handler() http.Handler {
v := Version()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
enc.Encode(v)
})
}