policy
policy copied to clipboard
CoreDNS external plugin to provide in-process policies as well as external policy services
firewall
Name
firewall - enables filtering of queries and responses based on expressions.
Description
The firewall plugin defines a list of rules that trigger a workflow action on a DNS query and its response. A rule list is an ordered set of rules that are evaluated in sequence. Rules can be an expression rule, or a policy engine rule. An expression rule has two parts: an action and an expression. When the rule is evaluated, first the expression is evaluated.
- If the expression evaluates to
true
the action is performed on the query and the rule list evaluation ceases. - If the expression does not evaluates to
true
then next rule in sequence is evaluated.
The firewall plugin can also refer to other policy engines to determine the action to take.
Syntax
firewall DIRECTION {
ACTION EXPRESSION
POLICY-PLUGIN ENGINE-NAME
}
-
DIRECTION indicates if the rule list will be applied to queries or responses. It can be
query
orresponse
. -
ACTION defines the workflow action to take if the EXPRESSION evaluates to
true
. If no actions are defined for thequery
DIRECTION, the default action is toblock
. Available actions:-
allow
: continue the DNS resolution process (i.e., continue to the next plugin in the chain) -
refuse
: interrupt the DNS resolution, reply with REFUSED response code -
block
: interrupt the DNS resolution, reply with NXDOMAIN response code -
drop
: interrupt the DNS resolution, do not reply (client will time out)
An action must be followed by an EXPRESSION, which defines the boolean expression for the rule. See Expressions section below.
-
-
POLICY-PLUGIN : is the name of another plugin that implements a firewall policy engine. ENGINE-NAME is the name of an engine defined in your Corefile. Requests/responses will be evaluated by that plugin policy engine to determine the action.
Expressions
Expressions follow a c-like expression format where the variables are either
the metadata
of CoreDNS or the fields of a DNS query/response. Common operators apply.
Expression Examples:
-
client_ip == '10.0.0.20'
-
type == 'AAAA'
-
type IN ('AAAA', 'A', 'TXT')
-
type IN ('AAAA', 'A') && name =~ 'google.com'
-
[mac/address] =~ '.*:FF:.*'
NOTE: because of the /
separator included in a label of metadata, those labels must be enclosed in
brackets [...]
.
Expression Variables
The following variables are supported for querying information in expressions. All values are strings (see atoi
function
below for arithmetic operations).
-
type
: type of the request (A, AAAA, TXT, ...) -
name
: name of the request (the domain name requested) -
class
: class of the request (IN, CH, ...) -
proto
: protocol used (tcp or udp) -
client_ip
: client's IP address, for IPv6 addresses these are enclosed in brackets:[::1]
-
size
: request size in bytes -
port
: client's port -
rcode
: response CODE (NOERROR, NXDOMAIN, SERVFAIL, ...) -
rsize
: raw (uncompressed), response size (a client may receive a smaller response) -
>rflags
: response flags, each set flag will be displayed, e.g., "aa, tc". This includes the qr bit as well -
>bufsize
: the EDNS0 buffer size advertised in the query -
>do
: the EDNS0 DO (DNSSEC OK) bit set in the query -
>id
: query ID -
>opcode
: query OPCODE -
server_ip
: server's IP address; for IPv6 addresses these are enclosed in brackets:[::1]
-
server_port
: client's port -
response_ip
: the IP address returned in the first A or AAAA record of the Answer section
Expression Functions
-
atoi(string)
: convert a string to a numeric value. -
incidr(ip, cidr)
: returns true ifip
is in the subnet defined bycidr
. -
random()
: returns a random floating point number in the range [0.0, 1.0).
Policy Engine Plugins
In addition to using the built-in action/expression syntax, the firewall plugin can use a policy engine plugin to evaluate policy.
To use a policy engine plugin, you'll need to compile the plugin into CoreDNS, then declare the plugin in your Corefile, and reference the plugin as an action of a firewall rule. See the "Using a Policy Engine Plugin" example below.
When authoring a new policy engine plugin, the plugin must implement the Engineer
interface defined in firewall/policy.
This repository includes two Policy Engine Plugins:
- themis - enables Infoblox's Themis policy engine to be used as a CoreDNS firewall policy engine
- opa - enables OPA to be used as a CoreDNS firewall policy engine.
External Plugin
Firewall and other associated policy plugins in this repository are external plugins, which means they are not included in CoreDNS releases. To use the plugins in this repository, you'll need to build a CoreDNS image with the plugins you want to add included in the plugin list. In a nutshell you'll need to:
- Clone https://github.com/coredns/coredns release, e.g.,
git clone -b v1.6.9 --depth 1 https://github.com/coredns/coredns .
- Add this plugin (
firewall:github.com/coredns/policy/plugin/firewall
), and any desired policy engines to plugin.cfg per instructions therein. Order in this file is important, as it dictates the order of plugin execution when processing a query. The firewall plugin should execute before plugins that generate responses. -
make -f Makefile.release DOCKER=your-docker-repo release
-
make -f Makefile.release DOCKER=your-docker-repo docker
-
make -f Makefile.release DOCKER=your-docker-repo docker-push
Examples
Client IP ACL
This example shows how to use firewall to create a basic client IP address-based ACL. Here 10.120.1.11
is expressly REFUSED.
Other clients in 10.120.0.0/24
and 10.120.1.0/24
are allowed. All other clients are not responded to.
. {
firewall query {
refuse client_ip == '10.120.1.11'
allow client_ip =~ '10\.120\.0\..*'
allow client_ip =~ '10\.120\.1\..*'
drop true
}
}
Domain Name Policy
Allow all queries for example.com. Allow A and AAAA queries for google.com. NXDOMAIN all other queries.
. {
firewall query {
allow name =~ 'example.com'
allow name =~ 'google.com' && (type == 'A' || type == 'AAAA')
block true
}
}
Response Policy
Allow all queries, but block all responses that contain an IP matching 10.120.1.*
in the first record
of the Answer section.
. {
firewall query {
allow true
}
firewall response {
block response_ip =~ '10\.120\.1\..*'
}
}
EDNS0 Metadata Policy
This example uses the metadata_edns0 plugin to define labels group_id
and client_id
with values extracted from EDNS0.
The firewall rules use those metadata to REFUSE any query without a group_id of 123456789
or client_id of ABCDEF
.
example.org {
metadata
metadata_edns0 {
group_id edns0 0xffed bytes
client_id edns0 0xffee bytes
}
firewall query {
refuse [metadata_edns0/client_id] != 'ABCDEF'
refuse [metadata_edns0/group_id] != '123456789'
allow true
}
}
Kubernetes Metadata Multi-Tenancy Policy
This example shows how firewall could be useful in a Kubernetes-based multi-tenancy application. It uses the kubernetes
plugin metadata to prevent Pods in certain Namespaces from looking up Services in other Namespaces.
Specifically, if the requesting Pod is in a Namespace beginning with 'tenant-', it permits only lookups to
Services that are in the same Namespace or in the 'default' Namespace. Note here that pods verified
is
required in the kubernetes plugin to enable the use of the [kubernetes/client-namespace]
metadata variable. Also note that
this is at the DNS level only, and does not prevent network access between tenant Namespaces, e.g., if Service IPs are known.
cluster.local {
metadata
kubernetes {
pods verified
}
firewall query {
allow [kubernetes/client-namespace] !~ '^tenant-'
allow [kubernetes/namespace] == [kubernetes/client-namespace]
allow [kubernetes/namespace] == 'default'
block true
}
}
Using a Policy Engine Plugin
The following example illustrates how the a policy engine plugin (themis in this example) can be used by the firewall plugin.
. {
firewall query {
themis myengine
}
themis myengine {
}
}