godoauth

package module
v0.0.0-...-7d703f1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 11, 2016 License: Apache-2.0 Imports: 19 Imported by: 2

README

godoauth - Go Docker Token Auth Service

Build Status

Godoauth is a token authenticator (introduced in Docker Registry v2) which uses Vault as a backend, developed as part of the Docker Global Hack Day #3 in Sydney.

The new token auth allows for fine-grained access control for private registries, especially important in large teams when many different projects share a registry.

Setup

Requirements:

If you haven't setup Go before, you need to first install Go and set a GOPATH (see https://golang.org/doc/code.html#GOPATH).

go get -u -f -t github.com/n1tr0g/...

This will fetch the code and build the command line tools into $GOPATH/bin (assumed to be in your PATH already). To start the Go Docker Authentication Service:

docker run -d -p 5002:5002 --restart=always --name godoauth \
  -v `pwd`/config:/etc/docker/godoauth \
  -v `pwd`/certs/:/certs \
  golja/godoauth

Configuration

Configuration is specified in a YAML file which can be set using the (-config option).

---
version: 0.1
log:
  level: info
  file: /tmp/godoauth.log
storage:
  vault:
    proto: http
    host: 127.0.0.1
    port: 8200
    auth_token: dbXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX
http:
  timeout: 5s
  addr: :5002
  tls:
    certificate: certs/server.pem
    key: certs/server.key
token:
   issuer: Token
   expiration: 800
   certificate: certs/server.pem
   key: certs/server.key

In some instances a configuration option is optional

Version
version: 0.1

The version option is optional. It specifies the configuration's version. It is expected to remain a top-level field, to allow for a consistent version check before parsing the remainder of the configuration file.

log

The log subsection is optional and configures the behavior of the logging system. The logging system outputs everything to stdout. You can adjust the granularity and format with this configuration section.

log:
  level: info
  file: /tmp/godoauth.log
Parameter Required Description
level no Sets the sensitivity of logging output. Permitted values are error, warn, info and debug. The default is info. TODO
file no Sets logging file.
storage

The storage subsection is required and it configures the data backend. Currently only vault is supported, but this may change in the future.

storage:
  vault:
    proto: http
    host: 127.0.0.1
    port: 8200
    auth_token: dbXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX
    timeout: 3s
vault
Parameter Required Description
proto yes Define vault proto backend. Permitted values are http and https
host yes Vault server address
port yes Vault server port
auth_token yes Vault authentication token used to connect to vault server. Usually generated via vault token-create
timeout no timeout for the communicatiob between godoauth and vault server. Default: 3s
http

The http option contains the config for the HTTP(S) server that hosts token authentication.

http:
  addr: :5002
  timeout: 5s
  tls:
    certificate: certs/server.pem
    key: certs/server.key
Parameter Required Description
addr yes The bind address for the server.
timeout yes After how many seconds the connection will be closed.
tls

The tls struct within http is optional and is used setup TLS for the server.

Parameter Required Description
certificate yes Absolute path to x509 cert file.
key yes Absolute path to x509 private key file.
token

The token subsection is required and contains the JWT token specific options.

token:
   issuer: Token
   expiration: 800
   certificate: certs/server.pem
   key: certs/server.key
Parameter Required Description
issuer yes Issuer of the token. This value must be the same on the registry. Usually you pass it as REGISTRY_AUTH_TOKEN_ISSUER=Issuer
expiration yes Token lifetime in in seconds.
certificate yes Path to x509 public cert file used for JWT signing.
key yes Path to x509 private key file used for JWT signing.

Development

If you want to contribute to godoauth you will need the latest Docker, Vault and a working Go environment.

Create Development SSL Certificates
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.pem
mkdir certs
cp server.pem server.key certs

NOTE: If you plan to test godoauth on a different host you will need a properly signed SSL or you must add --insecure-registry private.registry.io:5000 to the docker daemon parameters.

Docker Registry v2

On your Docker host start Registry v2

docker run -d -p 5000:5000 --restart=always --name registry \
  -v /root/data:/var/lib/registry \
  -v /root/certs:/certs \
  -e REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry \
  -e "REGISTRY_AUTH=token" \
  -e REGISTRY_AUTH_TOKEN_REALM=http://localhost:5002/auth \
  -e REGISTRY_AUTH_TOKEN_ISSUER=Token \
  -e "REGISTRY_AUTH_TOKEN_SERVICE=registry" \
  -e REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/server.pem \
  --restart=always \
  registry:2.1.1
Vault

For development purposes you can run Vault locally in development mode. All data will be stored in memory and there is no need to unseal the server.

Install
wget https://dl.bintray.com/mitchellh/vault/vault_VERSION_DISTRO.zip
unzip vault_VERSION_DISTRO.zip
cp vault /usr/local/bin
vault server -devel
Create service mount point
vault mount -path registry generic

The path mount point must match the service name defined in the registry above. The auth service has been designed to support multiple private registries, simply add another mount point in vault with corresponding users.

Add sample users
vault write registry/foo password=bar access="repository:linux/app:*;repository:linux/db:pull"

This will add the user foo with password bar to the registry service with full access to linux/app image and pull permission to linux/db image.

TODO

  • Add more testing
  • Add support for connection pools
  • More different backends

License

This project is distributed under Apache License, Version 2.0.

Documentation

Index

Constants

View Source
const (
	PrivPush    Priv = 1
	PrivPull         = 2
	PrivAll          = 3 // NB: equivlant to (PrivPush | PrivPull)
	PrivIllegal      = 4
)

Variables

View Source
var (
	ErrUnauthorized *HTTPAuthError = NewHTTPError("Unauthorized Access", http.StatusUnauthorized)
	ErrForbidden                   = NewHTTPError("Forbiden Access", http.StatusForbidden)
	ErrInternal                    = NewHTTPError("Internal server error", http.StatusInternalServerError)
)

Predefined internal error

Functions

This section is empty.

Types

type AuthRequest

type AuthRequest struct {
	Service  string
	Account  string
	Password string
	Scope    *Scope
}

AuthRequest holds the parsed client request

type Config

type Config struct {
	Version string     `yaml:"version,omitempty"`
	Log     Log        `yaml:"log,omitempty"`
	Storage Storage    `yaml:"storage,omitempty"`
	HTTP    ServerConf `yaml:"http"`
	Token   Token      `yaml:"token"`
}

func (*Config) LoadCerts

func (c *Config) LoadCerts() error

func (*Config) LoadFromFile

func (c *Config) LoadFromFile(path string) error

func (*Config) Parse

func (c *Config) Parse(rd io.Reader) error

type Duration

type Duration time.Duration

func (*Duration) UnmarshalText

func (d *Duration) UnmarshalText(b []byte) error

type HTTPAuthError

type HTTPAuthError struct {
	Code int
	// contains filtered or unexported fields
}

func HTTPBadRequest

func HTTPBadRequest(s string) (err *HTTPAuthError)

HTTPBadRequest returns *HTTPError with supplied informative string and error code 400.

func NewHTTPError

func NewHTTPError(s string, code int) (err *HTTPAuthError)

NewHTTPError creates new HTTPError with supplied error message and code. The message is displayed to the end user, so please be careful.

func (HTTPAuthError) Error

func (e HTTPAuthError) Error() string

func (*HTTPAuthError) Respond

func (e *HTTPAuthError) Respond(w http.ResponseWriter)

Respond sends the error code and message to the supplied ResponseWriter

type Handler

type Handler struct {
	*http.ServeMux
}

func NewHandler

func NewHandler(authHandler *TokenAuthHandler) *Handler

NewHandler returns a new instance of Handler built from a config.

type Log

type Log struct {
	Level string `yaml:"level,omitempty"`
	File  string `yaml:"file,omitempty"`
}

type Priv

type Priv uint

func NewPriv

func NewPriv(privilege string) Priv

func (Priv) Actions

func (p Priv) Actions() []string

func (Priv) Has

func (p Priv) Has(q Priv) bool

func (Priv) Valid

func (p Priv) Valid() bool

type Scope

type Scope struct {
	Type    string // repository
	Name    string // foo/bar
	Actions Priv   // Priv who would guess that ?
}

Scope definition

func (*Scope) UnmarshalText

func (s *Scope) UnmarshalText(b []byte) error

UnmarshalText decodes the Scope data from the standard text-form: <type>:<name>:<actions>

type ServerConf

type ServerConf struct {
	Addr    string        `yaml:"addr"`
	Timeout time.Duration `yaml:"timeout"`
	TLS     ServerTLS     `yaml:"tls"`
	// contains filtered or unexported fields
}

type ServerTLS

type ServerTLS struct {
	Certificate string `yaml:"certificate,omitempty"`
	Key         string `yaml:"key,omitempty"`
}

type Storage

type Storage struct {
	Vault Vault `yaml:"vault"`
}

type Token

type Token struct {
	Issuer      string `yaml:"issuer"`
	Expiration  int64  `yaml:"expiration"`
	Certificate string `yaml:"certificate"`
	Key         string `yaml:"key"`
	// contains filtered or unexported fields
}

type TokenAuthHandler

type TokenAuthHandler struct {
	// Main config file ... similar as in the server handler
	Config *Config
	// Account name of the user
	Account string
	// Service identifier ... One Auth server may be source of true for different services
	Service string
}

TokenAuthHandler handler for the docker token request Docker client will pass the following parameters in the request

service - The name of the service which hosts the resource. (required) scope - The resource in question. Can be speficied more time (required) account - name of the account. Optional usually get passed only if docker login

func (*TokenAuthHandler) CreateToken

func (h *TokenAuthHandler) CreateToken(scopes *Scope, service, account string) (string, error)

func (*TokenAuthHandler) ServeHTTP

func (h *TokenAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type UserInfo

type UserInfo struct {
	Username string
	Password string
	Access   map[string]Priv
}

UserInfo generic struct holding user data info generic to the backend user

type Vault

type Vault struct {
	Host      string        `yaml:"host"`
	Port      int           `yaml:"port"`
	AuthToken string        `yaml:"auth_token"`
	Proto     string        `yaml:"proto"`
	Pool      int           `yaml:"pool,omitempty"`
	Timeout   time.Duration `yaml:"timeout,omitempty"`
}

func (Vault) HostURL

func (v Vault) HostURL() string

type VaultClient

type VaultClient struct {
	Config *Vault
}

func (*VaultClient) RetrieveUser

func (c *VaultClient) RetrieveUser(ctx context.Context, namespace, user string) (*UserInfo, error)

RetrieveUser retrieve username/password/acl from Vault

func (*VaultClient) UnmarshalText

func (c *VaultClient) UnmarshalText(r io.Reader) (*UserInfo, error)

Notes

Bugs

  • we do not support anonymous images yet

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL