knockrd

package module
v0.0.18 Latest Latest
Warning

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

Go to latest
Published: Apr 25, 2023 License: MIT Imports: 32 Imported by: 0

README

knockrd

HTTP knocker daemon.

Description

knockrd is a daemon to allow access from restricted IP addresses works with nginx auth_request, AWS WAF v2, EC2 security groups or etc.

Usage

Usage of knockrd:
  -config string
    	config file name
  -debug
    	enable debug log
port: 9876
table_name: knockrd  # DynamoDB table name
ttl: 3600s           # Expiration time for allowed access

Usage with Nginx auth_request directive

knockrd works with nginx auth_request directive and Amazon DynamoDB.

Nginx example configuration.

http {
    server {
       listen 80;
       location = /allow {
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass http://127.0.0.1:9876;
       }
       location = /auth {
           internal;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass http://127.0.0.1:9876;
       }
       location / {
           auth_request /auth;
           root /var/www/htdocs;
       }
    }
}

knockrd process must have IAM policies which allows actions as below.

  • dynamodb:DeleteItem
  • dynamodb:GetItem
  • dynamodb:PutItem
  • dynamodb:UpdateItem
  • dynamodb:DescribeTable
  • dynamodb:DescribeTimeToLive
  • dynamodb:CreateTable (* if a table in config is not exist)
  • dynamodb:UpdateTimeToLive (*)
Authorization Flow
  1. A user accesses to /allow.
    • This location must be protected by other methods like OAuth or etc.
  2. knockrd shows HTML form to allow access from the user's IP address.
  3. The user pushes the "Allow" button.
  4. knockrd store the IP address to the backend(DynamoDB) with TTL.
  5. The user accesses to other locations.
  6. Nginx auth_request directive requests to knockrd /auth.
  7. knockrd compares the IP address with the backend and returns 200 OK or 403 Forbidden.
  8. Nginx allows or denies the user's request based on the knockrd response.
  9. DynamoDB expires the item after TTL.

Usage with AWS WAF v2 IP Set (serverless)

knockrd works with AWS WAF v2, AWS Lambda and Amazon DynamoDB.

Prepare an IAM Role for lambda functions. arn:aws:iam::{your account ID}:role/knockrd_lambda The role must have policies which allows actions as below.

  • wafv2:GetIPSet
  • wafv2:UpdateIPSet
  • dynamodb:DeleteItem
  • dynamodb:GetItem
  • dynamodb:PutItem
  • dynamodb:UpdateItem
  • dynamodb:DescribeTable
  • dynamodb:DescribeTimeToLive
  • dynamodb:CreateTable (* if a table in config is not exist)
  • dynamodb:UpdateTimeToLive (*)

Prepare IP sets for AWF WAF v2.

Prepare config.yaml for the IP sets.

table_name: knockrd  # DynamoDB table name
ttl: 300s
ip-set:
  v4:
    id: ddcdf8ad-251c-4c8f-b12f-05628b87beb6
    name: knockrd
    scope: REGIONAL

Deploy two lambda functions, knockrd-http and knockrd-stream in lambda directory with the IAM role and config.yaml. The example of lambda directory uses lambroll for deployment.

Authorization Flow
  1. A user accesses to /allow provided by knockrd-http.
    • This location must be protected by other methods like OAuth or etc.
  2. knockrd-http shows HTML form to allow access from the user's IP address.
  3. The user pushes the "Allow" button.
  4. knockrd-http store the IP address to the backend(DynamoDB) with TTL.
    • knockrd-stream adds the address to AWS WAF IP Set by events on the dynamodb stream.
  5. The user accesses to other locations.
  6. AWS WAF allows or denies the user's request based on the ip sets.
  7. DynamoDB expires the item after TTL.
    • knockrd-stream deletes from IP set by events on the stream.

Usage with EC2 Security Group

knockrd works with EC2 security groups, AWS Lambda and Amazon DynamoDB.

Prepare an IAM Role for lambda functions. arn:aws:iam::{your account ID}:role/knockrd_lambda The role must have policies which allows actions as below.

  • ec2:AuthorizeSecurityGroupIngress
  • ec2:RevokeSecurityGroupIngress
  • dynamodb:DeleteItem
  • dynamodb:GetItem
  • dynamodb:PutItem
  • dynamodb:UpdateItem
  • dynamodb:DescribeTable
  • dynamodb:DescribeTimeToLive
  • dynamodb:CreateTable (* if a table in config is not exist)
  • dynamodb:UpdateTimeToLive (*)

Prepare EC2 security groups.

Prepare config.yaml for the security groups.

table_name: knockrd  # DynamoDB table name
ttl: 86400s
security_groups:
  - id: sg-xxxxxxxx # ID of Security Group
    from_port: 22   # From port
    to_port: 22     # To port
    protocol: tcp   # IP protocol (tcp, udp, icmp or number)

Deploy two lambda functions, knockrd-http and knockrd-stream in lambda directory with the IAM role and config.yaml. The example of lambda directory uses lambroll for deployment.

Authorization Flow
  1. A user accesses to /allow provided by knockrd-http.
    • This location must be protected by other methods like OAuth or etc.
  2. knockrd-http shows HTML form to allow access from the user's IP address.
  3. The user pushes the "Allow" button.
  4. knockrd-http store the IP address to the backend(DynamoDB) with TTL.
    • knockrd-stream adds the address to security groups by events on the dynamodb stream.
  5. The user accesses to resources which have the security groups.
  6. Security groups allows or denies the user's request based on rules.
  7. DynamoDB expires the item after TTL.
    • knockrd-stream deletes address from security groups by events on the stream.

Usage with Consul and consul-template

knockrd works with Consul, AWS Lambda and Amazon DynamoDB.

Authorization Flow
  1. A user accesses to /allow provided by knockrd.
    • This location must be protected by other methods like OAuth or etc.
  2. knockrd shows HTML form to allow access from the user's IP address.
  3. The user pushes the "Allow" button.
  4. knockrd store the IP address to the backend(DynamoDB) with TTL.
    • knockrd-stream adds the address to Consul KV by events on the dynamodb stream.
  5. consul-template renders a configuration file for nginx with items in Consul KV.
  6. The user accesses to other locations.
  7. nginx allows or denies the user's request based on the configuration file.
  8. DynamoDB expires the item after TTL.
    • knockrd-stream deletes from Consul KV by events on the stream.
  9. consul-template] renders a configuration file.

A example of consul-template's template and consul-template command for nginx.

location / {
  {{ range ls "knockrd/allowed" }}
  allow {{ .Value }};{{ end }}
  deny all;
}
# consul-template -template "allowed.ctmpl:/etc/nginx/allowed.conf:service nginx reload"

consul-template renders a configuration file by the template when Key-Values are changed on Consul, and then reload nginx.

Configuration

port: 9876   # listen port for knockrd
proxy_protocol: true # enable PROXY protocol (default false)
table_name: mytable_for_knockrd # DynamoDB table name
real_ip_from:
  - 192.168.0.0/16   # list of trusted CIDR to accept real_ip_header
real_ip_header: X-Forwarded-For # header whose value will be used to replace the client address
real_ip_from_cloudfront: true # append CloudFront CIDRs to real_ip_from by https://ip-ranges.amazonaws.com/ip-ranges.json
ttl: Time to live to allow IP address
cache_ttl: TTL for knockrd in memory cache for allowed IP addresses
aws:
  region: us-east-1  # AWS region of DynamoDB & Regional WAFv2 IP Set
  endpoint:          # AWS endpoints for debug
ip-set:
  v4:
    id: xxxx        # ID of WAFv2 IP Set for IPv4
    name: foo       # Name of WAFv2 IP Set
    scope: REGIONAL # Scope of WAFv2 IP Set (REGIONAL or CLOUDFRONT)
  v6:
    id: xxxx        # ID of WAFv2 IP Set for IPv6
    name: foo       # Name of WAFv2 IP Set
    scope: REGIONAL # Scope of WAFv2 IP Set (REGIONAL or CLOUDFRONT)
security_groups:
  - id: sg-xxxxxxxx # ID of Security Group
    from_port: 22   # From port
    to_port: 22     # To port
    protocol: tcp   # IP protocol (tcp, udp, icmp or number)
cousul:
  address: 127.0.0.1:8500 # address of Consul agnet
  scheme: http            # scheme for access to consul agent

See default values for configuration at Constants/Variables.

LICENSE

MIT License

Copyright (c) 2020 FUJIWARA Shunichiro

Documentation

Index

Constants

View Source
const (
	DefaultPort     = 9876
	DefaultTable    = "knockrd"
	DefaultTTL      = time.Hour
	DefaultCacheTTL = 10 * time.Second
)

Variables

View Source
var DefaultConsulKVPath = "knockrd/allowed"
View Source
var DefaultRealIPFrom = []string{
	"10.0.0.0/8",
	"172.16.0.0/12",
	"192.168.0.0/16",
	"127.0.0.0/8",
	"fe80::/10",
	"::1/128",
}
View Source
var Timeout = 30 * time.Second

Functions

func JSONString added in v0.0.9

func JSONString(s interface{}) string

func NewStreamHandler added in v0.0.2

func NewStreamHandler(conf *Config) func(context.Context, events.DynamoDBEvent) error

NewStreamHandler creates a DynamoDB Stream handler function

func Run

func Run(conf *Config, stream bool) error

Run runs knockrd

Types

type AWSConfig

type AWSConfig struct {
	Region   string `yaml:"region"`
	Endpoint string `yaml:"endpoint"`
}

type Backend

type Backend interface {
	Set(string) error
	Get(string) (bool, error)
	Delete(string) error
	TTL() time.Duration
}

func NewCachedBackend

func NewCachedBackend(backend Backend, ttl time.Duration) (Backend, error)

func NewDynamoDBBackend

func NewDynamoDBBackend(conf *Config) (Backend, error)

type CachedBackend

type CachedBackend struct {
	// contains filtered or unexported fields
}

func (*CachedBackend) Delete

func (b *CachedBackend) Delete(key string) error

func (*CachedBackend) Get

func (b *CachedBackend) Get(key string) (bool, error)

func (*CachedBackend) Set

func (b *CachedBackend) Set(key string) error

func (*CachedBackend) TTL added in v0.0.1

func (b *CachedBackend) TTL() time.Duration

type Config

type Config struct {
	Port          int    `yaml:"port"`
	ProxyProtocol bool   `yaml:"proxy_protocol"`
	TableName     string `yaml:"table_name"`

	RealIPFrom           []string `yaml:"real_ip_from"`
	RealIPFromCloudFront bool     `yaml:"real_ip_from_cloudfront"`
	RealIPHeader         string   `yaml:"real_ip_header"`

	OIDCAllowed *ConfigOIDCAllowed `yaml:"oidc_allowed"`

	TTL      time.Duration `yaml:"ttl"`
	CacheTTL time.Duration `yaml:"cache_ttl"`
	AWS      AWSConfig     `yaml:"aws"`
	IPSet    *struct {
		V4 *IPSetConfig `yaml:"v4"`
		V6 *IPSetConfig `yaml:"v6"`
	} `yaml:"ip-set"`
	Consul         *ConsulConfig          `yaml:"consul"`
	SecurityGroups []*SecurityGroupConfig `yaml:"security_groups"`
}

func LoadConfig

func LoadConfig(path string) (*Config, error)

func (*Config) Setup

Setup setups resources by config

func (*Config) String

func (c *Config) String() string

type ConfigOIDCAllowed added in v0.0.12

type ConfigOIDCAllowed struct {
	EmailDomains   []string `yaml:"email_domains"`
	EmailAddresses []string `yaml:"email_addresses"`
}

type ConsulConfig added in v0.0.2

type ConsulConfig struct {
	Address    string `yaml:"address"`
	Scheme     string `yaml:"scheme"`
	Datacenter string `yaml:"datacenter"`
	KVPath     string `yaml:"kv_path"`
}

type DynamoDBBackend

type DynamoDBBackend struct {
	TableName string
	// contains filtered or unexported fields
}

func (*DynamoDBBackend) Delete

func (d *DynamoDBBackend) Delete(key string) error

func (*DynamoDBBackend) Get

func (d *DynamoDBBackend) Get(key string) (bool, error)

func (*DynamoDBBackend) Set

func (d *DynamoDBBackend) Set(key string) error

func (*DynamoDBBackend) TTL

func (d *DynamoDBBackend) TTL() time.Duration

type IPSetConfig

type IPSetConfig struct {
	ID    string `yaml:"id"`
	Scope string `yaml:"scope"`
	Name  string `yaml:"name"`
}

type Item

type Item struct {
	Key     string `dynamo:"Key,hash"`
	Expires int64  `dynamo:"Expires"`
}

type SecurityGroupConfig added in v0.0.9

type SecurityGroupConfig struct {
	ID       string `yaml:"id"`
	FromPort int64  `yaml:"from_port"`
	ToPort   int64  `yaml:"to_port"`
	Protocol string `yaml:"protocol"`
}

type View added in v0.0.4

type View struct {
	IPAddr    string
	CSRFToken string
	Message   string
}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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