API Object - registered_service
- Updated on Apr 28, 2023
Service Metadata
type Metadata struct {
Name string `json:"name"`
Description string `json:"description"`
ClusterName string `json:"cluster"`
}
Service Spec
type Spec struct {
Attributes `json:"attributes"`
Backend `json:"backend"`
CertSettings `json:"cert_settings"`
HTTPSettings `json:"http_settings"`
ClientCIDRs []ClientCIDRs `json:"client_cidrs"`
}
type Attributes
Attributes define the major user- and admin- visible properties of a Service.
type Attributes struct {
// TLSSNI (optional) tells Netagent to use Server Name Indication (SNI) for
// TLS connections.
// If TLSSNI is NOT set, Netagent transparently forwards on all TCP
// connections for Policy validation and then onto its original
// destination.
// If TLSSNI is set, Netagent will reject all non-TLS connections;
// it will only forward on TLS connections where the SNI matches
// for Policy validation
TLSSNI []string `json:"tls_sni"`
// FrontendAddresses (mandatory) is used to specifcy the IP addresses and
// Ports the service listens on.
// Netagent will intercept traffic that matches FrontendAddresses and,
// if a Policy is attached, enforce policies
FrontendAddresses []FrontendAddress `json:"frontend_addresses"`
// HostTagSelector (optional) tells Netagent to intercept FrontendAddresses
// on only a specific subset of Hosts
HostTagSelector []map[string]string `json:"host_tag_selector"`
DisablePrivateDns bool `json:"disable_private_dns"`
}
type FrontendAddress
FrontendAddress is used to specify the IP addresses and Ports the service listens on
type FrontendAddress struct {
// CIDR (optional) is a list of IP addresses specified in CIDR notation
// that the Service should match
CIDR string `json:"cidr"`
// Port (mandatory) is the port that the Service listens on
Port string `json:"port"`
}
type CertSettings
CertSettings specifies the X.509 server certificate to use for this Service
type CertSettings struct {
// Letsencrypt flag will be used
// whether to request a letsencrypt certificate for given domains
Letsencrypt bool `json:"letsencrypt"`
// DNSNames specifies how to populate the CommonName field in the X.509
// server certificate for this Service;
// if DNSNames is not specified the CommonName field will be set to the
// ServiceName
DNSNames []string `json:"dns_names"`
CustomTLSCert `json:"custom_tls_cert"`
}
type HTTPSettings
HTTPSettings is used by HTTP services for provide specific functionality
type HTTPSettings struct {
Enabled bool `json:"enabled"`
OIDCSettings `json:"oidc_settings"`
HTTPHealthCheck `json:"http_health_check"`
ExemptedPaths `json:"exempted_paths"`
*CustomTrustCookie `json:"custom_trust_cookie"`
// Headers is a list of HTTP headers to add to every request sent to the Backend;
// the key of the map is the header name, and the value is the header value you want.
// The header value may be constructed using Go template syntax, such as {{.Email}}
// referencing values in Banyan's JWT TrustToken
Headers map[string]string `json:"headers" toml:"headers"`
TokenLoc *TokenLocation `json:"token_loc,omitempty" toml:"token_loc"`
}
type TokenLocation
TokenLocation is used by web services to indicate where in HTTP request, token/apikey could be found. This could be used to skip OIDC, but still authenticate the requests using api-keys/tokens.
type TokenLocation struct {
QueryParam string `json:"query_param,omitempty"`
AuthorizationHeader bool `json:"authorization_header,omitempty"`
CustomHeader string `json:"custom_header,omitempty"`
}
type ClientCIDRs
ClientCIDRs is used in environments with Network Address Translation (NAT) to list the IP addresses that are used to access the Service; Netagent will then automatically intercept traffic to these IP addresses.
type ClientCIDRs struct {
// Addresses is a list of IP addresses specified in CIDR notation
Addresses []CIDRAddress `json:"addresses"`
// HostTagSelector tells Netagent to set Client CIDRs on only a specific
// subset of Hosts
HostTagSelector []map[string]string `json:"host_tag_selector"`
// Clusters tells Netagent to set Client CIDRs on only a specific subset
// of Clusters
Clusters []string `json:"clusters"`
}
type CIDRAddress
CIDRAddress uses the Classless Inter-Domain Routing (CIDR) format for flexible allocation of IP addresses
type CIDRAddress struct {
CIDR string `json:"cidr"`
Ports string `json:"ports"`
}
type OIDCSettings
OIDCSettings provides Netagent specific parameters needed to use OpenID Connect to authenticate an Entity for access to a Service
type OIDCSettings struct {
// Enabled (mandatory) turns on the OIDC capability
Enabled bool `json:"enabled" toml:"enabled"`
// ServiceDomainName (mandatory, ex: https://myapp.myorg.com:8123) is
// the URL used to access the service
ServiceDomainName string `json:"service_domain_name" toml:"service_domain_name"`
// PostAuthRedirectPath (optional, default: /) is the path to return the
// user to after OpenID Connect flow
PostAuthRedirectPath string `json:"post_auth_redirect_path" toml:"post_auth_redirect_path"` // has default value "/"
// APIPath (optional, default: /api) is the path serving AJAX requests;
// if a request is not authenticated, paths starting with the APIPath
// will receive a 403 Unauthorized response,
// instead of a 302 Redirect to the authentication provider
APIPath string `json:"api_path" toml:"api_path"` // has default value "/api"
TrustCallBacks map[string]string `json:"trust_callbacks" toml:"trust_callbacks"` // for multiple redirect URLs
// SuppressDeviceTrustVerification disables Device Trust Verification for a service if set to true
SuppressDeviceTrustVerification bool `json:"suppress_device_trust_verification" toml:"suppress_device_trust_verification"`
}
type HTTPHealthCheck
HTTPHealthCheck tells Netagent that specific HTTP paths should be exempted from access control policies
type HTTPHealthCheck struct {
// Enabled (mandatory) turns on the HTTP health check capability
Enabled bool `json:"enabled"`
// Path (mandatory) specifies the HTTP health check path
Path string `json:"path"`
// Method (optional, default: GET) specifies the health check HTTP method
Method string `json:"method"`
// UserAgent (optional, default: no check) is a string to check for in
// the HTTP user-agent header
UserAgent string `json:"user_agent"`
// FromAddress (optional, default: allow all) is a string array of
// allowed source addresses of the health checker
FromAddress []string `json:"from_address"`
// HTTPS (optional, default: false) specifies that the health check
// uses HTTPS instead of HTTP
HTTPS bool `json:"https"`
}
type CustomTrustCookie
CustomTrustCookie allows customizing attributes of the Banyan trust cookie
type CustomTrustCookie struct {
// SameSite: "", "default", "lax", "none", "strict"
SameSite string `json:"same_site,omitempty"`
}
type CustomTLSCert
CustomTLSCert enables Netagent to override the default behavior of obtaining a X.509 server certificate for this Service from Shield, and instead use a TLS certificate on the local file system
type CustomTLSCert struct {
// Enabled (mandatory) turns on the custom TLS certificate capability
Enabled bool `json:"enabled"`
// CertFile (mandatory) specifies the local path of the Public
// Certificate (ex: /etc/letsencrypt/live/intks.net-0001/fullchain.pem)
CertFile string `json:"cert_file"`
// KeyFile (mandatory) specifies the local path of the Private
// Key (ex: /etc/letsencrypt/live/www.example.com/privkey.pem)
KeyFile string `json:"key_file"`
}
type Backend
Backend specifies how Netagent, when acting as a reverse proxy, forwards incoming “frontend connections” to a backend workload instance that implements a registered service.
type Backend struct {
// BackendTarget specifies the backend workload instance's address or name,
// ports, and TLS properties.
BackendTarget `json:"target"`
// BackendDNSOverrides is an optional section that specifies name-to-address or name-to-name mappings.
// Name-to-address mapping could be used instead of DNS lookup. Format is "FQDN: ip_address".
// Name-to-name mapping could be used to override one FQDN with the other. Format is "FQDN1: FQDN2"
// Example: name-to-address -> "internal.myservice.com" : "10.23.0.1"
// name-to-name -> "exposed.service.com" : "internal.myservice.com"
BackendDNSOverrides map[string]string `json:"dns_overrides"`
// BackendWhitelist is an optional section that indicates the allowed names for
// the backend workload instance. If this field is populated, then the backend name must
// match at least one entry in this field list to establish connection with the backend service.
// The names in this list are allowed to start with the wildcard character "*" to match more
// than one backend name.
// This field is used generally with HttpConnect=FALSE. For all HttpConnect=TRUE cases, or where
// more advanced backend defining patterns are required, use BackendAllowPatterns.
BackendWhitelist []string `json:"whitelist"`
// BackendAllowPatterns is an optional section defines the patterns for the backend workload
// instance. If the BackendAllowPatterns is populated, then the backend must match at least one entry
// in this list to establish connection with the backend service.
// Note that this field is effective only when BackendWhitelist is not populated.
// If BackendWhitelist and BackendAllowPatterns are both not populated, then all backend
// address/name/port are allowed.
// This field could be used with httpConnect set to TRUE or FALSE. With HttpConnect set to FALSE,
// only backend hostnames are supported, all other fields are ignored. With HttpConnect set to TRUE,
// all fields of BackendAllowPatterns are supported and effective.
BackendAllowPatterns []BackendAllowPattern `json:"allow_patterns,omitempty"`
// HttpConnect is an optional setting that indicates to use HTTP Connect request to derive
// the backend target address.
HttpConnect bool `json:"http_connect,omitempty"`
}
type BackendTarget
BackendTarget specifies the backend workload instance’s name, ports, and TLS properties.
type BackendTarget struct {
// NameDelimiter is an optional string used to separate the initial component of
// the frontend domain name into multiple parts, e.g., if name delimiter is "--" and
// the frontend domain name is "abc--def.example.com", then the resulting parts are
// "abc", "def", "example", and "com". These parts can be used in the backend target
// name, e.g., "{{index .Parts 0}}.{{index .Parts 1}}.ec2.internal" (which would
// get instantiated as "abc.def.ec2.internal").
NameDelimiter string `json:"name_delimiter,omitempty" toml:"name_delimiter,omitempty"`
// Name specifies the name of the backend workload instance.
// If it is the empty string, then netagent will use the destination
// IP address of the incoming frontend connection as the workload
// instance's address.
// If non-empty, Name can be a plain string, or a Go template string
// containing "{{ .Name }}" and/or "{{ .Domain }}" for extracting portions
// of the client SNI. For example, if SNI is "www.example.com",
// the "{{ .Name }}" corresponds to "www" and the "{{ .Domain }}"
// corresponds to "example.com".
// As a concrete example, "{{ .Name }}-internal.{{ .Domain }}"
// maps to "www-internal.example.com" for client SNI "www.example.com".
Name string `json:"name"`
// Port specifies the backend server's TCP port number.
Port string `json:"port"`
// TLS indicates whether the connection to the backend server uses TLS.
TLS bool `json:"tls"`
// TLSInsecure indicates whether the backend TLS connection does not
// validate the server's TLS certificate"
TLSInsecure bool `json:"tls_insecure"`
// ClientCertificate indicates whether to provide netagent's client TLS
// certificate to the server if the server asks for it in the TLS handshake.
ClientCertificate bool `json:"client_certificate"`
}
type BackendAllowPattern struct {
// Allowed hostnames my include a leading and/or trailing wildcard character "*"
// to match multiple hostnames
Hostnames []string `json:"hostnames,omitempty"`
// Host may be a CIDR such as 10.1.1.0/24
CIDRs []string `json:"cidrs,omitempty"`
// List of allowed ports and port ranges
Ports *BackendAllowPorts `json:"ports,omitempty"`
}
type BackendAllowPorts struct {
// List of allowed ports
PortList []int `json:"port_list,omitempty"`
// List of allowed port ranges
PortRanges []PortRange `json:"port_ranges,omitempty"`
}
type PortRange struct {
// Min and Max values of the port range
Min int `json:"min"`
Max int `json:"max"`
}
Example-1 Backend JSON
This example fills in two fields just for demonstration.
In particular, both ipv4
and name
are filled in,
but really a valid spec would have only one of the two fields filled in.
{
"backend": {
"target": {
"name": "{{ .Name }}-internal.{{ .Domain }}",
"port": "8080",
"tls": true,
"tls_insecure": false,
"client_certificate": true
},
"dns_overrides": {
"jira-internal.foo": "10.0.142.5",
"gitlab-internal.foo": "10.0.142.6",
"phase1-test.foo": "10.0.152.27",
"phase2-test.foo": "10.0.152.38"
},
"whitelist": [
"jira-internal.foo",
"gitlab-internal.foo",
"*-test.foo"
]
}
}
Example-2 Backend JSON
This example is similar to the previous one, except it shows a usecase with HttpConnect=TRUE. We are using the BackendAllowPatterns field instead of BackendWhitelist field, since it provides the ability to specify the allowed backend services by CIDR/hostnames/ports etc.
{
"backend": {
"dns_overrides": {
"jira-internal.foo": "10.0.142.5",
"gitlab-internal.foo": "10.0.142.6",
"phase1-test.foo": "10.0.152.27",
"phase2-test.foo": "10.0.152.38"
},
"whitelist": [],
"allow_patterns": [
{
"hostnames": [
"jira-internal.foo",
"gitlab-internal.foo"
],
"cidrs": [
"10.0.34.2",
"34.70.156.134"
],
"ports": {
"port_list": [
80,
5901
],
"port_ranges": [
{
"Min": 5905,
"Max": 5911
}
]
}
},
{
"hostnames": [
"*test.foo"
],
}
],
"http_connect": true
}
}
type ExemptedPaths
ExemptedPaths tells Netagent that specific HTTP paths should be whitelisted/exempted from OIDC authentication
type ExemptedPaths struct {
// Enabled (mandatory) - turns on the HTTP path whitelist capability
Enabled bool `json:"enabled"`
// Paths (optional) - specifies the HTTP whitelist paths. HTTP Requests to these matching paths
// will be exempted from OIDC. Paths could be defined as wildcards like: /*, /banyan/*, /banyan*.
// Only HTTP request paths are matched, no other fields of the HTTP request header is checked.
//
// For more complex matching rules, use Patterns. HTTP requests are first matched with Paths defined here.
// If there is no match, only then requests are matched with Patterns.
Paths []string `json:"paths,omitempty"`
// Patterns (optional) - specifies the attributes matched in HTTP request to exempt from OIDC authentication.
// Check the Pattern object description below for details.
Patterns []Pattern `json:"patterns,omitempty"`
}
type Pattern
Pattern tells Netagent to exempt HTTP requests based on matching HTTP request attributes, such as source IP, host, headers, methods, paths, etc. For example, use this section when exempting CORS requests by source IP address.
type Pattern struct {
// Template (optional) is populated by the Banyan console UI
Template string `json:"template,omitempty" toml:"template"`
// SourceCIDRs (optional) - specifies the source IP address of the HTTP request. The matching request should match or should be in the range of the CIDR specified.
// SourceCIDRs is an array and multiple CIDRs with/without prefix could be specified like, 127.0.0.1, 192.168.1.0/29, 10.0.0.0/8 etc.
// If source-ip matching is not required, you many skip this field.
SourceCIDRs []string `json:"source_cidrs,omitempty" toml:"source_cidrs"`
// Hosts (mandatory) is the host/origin header values in the HTTP request, please check "Host" structure for details
Hosts []Host `json:"hosts" toml:"hosts"`
// Methods (mandatory) matches the HTTP request methods. The matching request will have any one of the listed methods.
// To list all the methods supported "like GET/POST/OPTIONS etc.
// ["*"] value will have "DONT CARE" effect and will skip matching methods.
Methods []string `json:"methods"`
// MandatoryHeaders (mandatory) matches the HTTP request headers. The matching request will have all of the headers listed.
// To list all the headers that a matching HTTP request should have for instance "Content-Type"/"Access-Control-Allow-Origin" etc.
// ["*"] will have "DONT CARE" effect and will skip matching headers.
MandatoryHeaders []string `json:"mandatory_headers"`
// Paths (mandatory) matches the HTTP request URI. The matching request will have any one of the paths/strings listed.
// Paths could be defined as wildcards like: /*, /banyan/*, /banyan*
//
// In addition, these paths also allow Golang RegExp as defined at: https://pkg.go.dev/regexp
// Note that this is an exclusive implementation. If you use trailing wilcards as defined above,
// then the path will *not* be treated as a RegExp.
Paths []string `json:"paths"`
}
type Host struct {
// OriginHeader (mandatory) - list of web host addresses that match the Origin header in the HTTP request.
// The value should have "scheme:host:port", ex: "https://www.banyansecurity.io:443". This field supports single domain wildcards also, like
// https://*.banyansecurity.com or https://api.*.banyansecurity.com:443
OriginHeader []string `json:"origin_header"`
// Target (mandatory) - list of web host addresses that match the Host header in the HTTP request.
// The value should have "scheme:host:port", ex: https://www.banyansecurity.io:443. This field supports single domain wildcards also, like
// https://*.banyansecurity.com or https://api.*.banyansecurity.com:443. This should be filled only while hosting multi-domain services. In single domain
// service deployments, this field to be filled as [*] to have "DONT CARE" effect.
Target []string `json:"target"`
}
Example - Single Domain case
Consider domain-b
allowing CORS requests originating from domain-a
.
To achieve the above result, the service definition in JSON is:
- OriginHeader : Will have the content of origin header
- target : Will be DONT CARE
*
{
"exempted_paths": {
"enabled": true,
"paths": [ ],
"patterns": [
{
"hosts": [
{
"origin_header": ["https://www.domain-a.com:443"],
"target": ["*"]
}
],
"methods": [
"GET", "POST", "OPTIONS"
],
"mandatory_headers": [
"origin"
],
"paths": [
"/index.html"
]
}
]
}
}
Example - Multi-Domain case
Consider multiple subdomain services being protected by the same Netagent. Ex: Considering app.domain.com
, api.domain.com
, games.domain.com
, everybody.domain.com
are the hosted services.
If api.domain.com
wants to support CORS request and allow only those originating from app.domain.com
and games.domain.com
.
To achieve the above result, the service definition in JSON is:
- OriginHeader : Will have the content of origin header which is
app.domain.com
,games.domain.com
- Target: As the registered service matches
*.domain.com
, the exact targetapi.domain.com
that is receiving the CORS request needs to be specified
{
"exempted_paths": {
"paths": [],
"enabled": true,
"patterns": [
{
"hosts": [
{
"origin_header": [
"https://www.app.domain.com:443",
"https://www.games.domain.com:443"
],
"target": [
"https://www.api.domain.com:443"
]
}
],
"methods": [
"GET",
"POST",
"OPTIONS"
],
"mandatory_headers": [
"origin"
],
"paths": [
"/index.html"
]
}
]
}
}
Example - Single Domain case with source CIDR exemption
Consider domain-b
allowing CORS requests originating from domain-a
. If this has to be applied to requests with specific source IP address, say 30.0.0.0/24 or 10.0.0.5/32.
To achieve the above result, the service definition in JSON is:
- SourceCIDRs : list the above source CIDRs to match
- OriginHeader : Will have the content of origin header
- target : Will be DONT CARE
*
{
"exempted_paths": {
"enabled": true,
"paths": [],
"patterns": [
{
"source_cidrs": ["30.0.0.0/24", "10.0.0.5/32"],
"hosts": [
{
"origin_header": ["https://www.domain-a.com:443"],
"target": ["*"]
}
],
"methods": [
"GET", "POST", "OPTIONS"
],
"mandatory_headers": [
"origin"
],
"paths": [
"/index.html"
]
}
]
}
}
Example - Just Source CIDR exemption
Consider the scenario to exempt OIDC for HTTP requests with specific source IP address, say 20.0.0.1 or 192.168.1.0/29.
To achieve the above result, the service definition in JSON is:
- SourceCIDRs : list the above source CIDRs to match
- Rest of the patterns field to have DONT-CARE value as below
{
"exempted_paths": {
"enabled": true,
"paths": [],
"patterns": [
{
"source_cidrs": ["20.0.0.1", "192.168.1.0/29"],
"hosts": [
{
"origin_header": ["*"],
"target": ["*"]
}
],
"methods": [
"*"
],
"mandatory_headers": [
"*"
],
"paths": [
"/*"
]
}
]
}
}
Example - using Golang RegExp to exempt certain paths from OIDC authentication
Consider the case where you’d like to exempt all JS requests.
The service definition in JSON is:
- Path: regular expression (using Golang RegExp as defined here: https://pkg.go.dev/regexp) that all targets all requests ending with
.js
- Rest of the patterns field to have DONT-CARE value as below
"exempted_paths": {
"enabled": true,
"paths": [],
"patterns": [
{
"hosts": [
{
"origin_header": ["*"],
"target": ["*"]
}
],
"methods": [
"*"
],
"mandatory_headers": [
"*"
],
"paths": [
"/.+.js"
]
}
]
}
Headers
Headers is a list of HTTP headers to add to every authenticated request sent to the Backend; the key of the map is the header name, and the value is the header value you want. The header value may be constructed using Go template syntax, such as {{.Email}}
, referencing values in Banyan’s JWT TrustToken.
Example - string constants
A simple example is depicted below. This will add a HTTP header X-Foo: bar
to all requests.
{
"headers": {
"X-Foo": "bar"
}
}
Example - templating
A more complex example is depicted below.
{
"headers": {
"X-Email": "{{.Email}}",
"X-Groups": "{{.Groups}}",
"X-DevicePlatform": "{{.Platform}}",
"Y-User": "{{.Email.User}}",
"Y-Domain": "{{.Email.Domain}}",
"Z-Token": "{{.JWT}}"
}
}
The template values will be filled out from a Banyan TrustToken, that looks like:
{
"at_hash": "sJEbAwFXmfUVTDiPuBJEEQ",
"aud": "Yeqzf9nMdKzCnal-1SeJAg",
"device_id": "9c93cb4788be663fedf2",
"email": "alex@example.com",
"email_verified": true,
"exp": 1616091761,
"groups": [
"Everyone",
"Admins"
],
"https://banyansecurity.io": {
"device_ownership": "Corporate Dedicated",
"is_staged_install": false,
"mdm_present": false,
"orgname": "test-drive",
"platform": "Windows"
},
"iat": 1616005361,
"iss": "https://test-drive.trust-preview.banyanops.com/v2",
"name": "Adam Admin",
"nonce": "D3zDrJaFolAiI5KnwEvpr",
"preferred_username": "alex@example.com",
"serial_number": "9c93cb4788be663fedf2",
"sub": "ChQwMHU1b3E4OXU5aWxFZDVnVTVkNhIUdGVzdC1kcml2ZS1jb25uZWN0b3I"
}
The HTTP headers sent to the backend would then be:
X-Email: alex@example.com
X-Groups: Everyone,Admins
X-DevicePlatform: Windows
Y-User: adam
Y-Domain: medsoft.digital
Z-Token: eyJhbGci...
Variables
The following variables in the TrustToken are available for use in the template syntax:
DeviceID string
SerialNumber string
Platform string
DeviceOwnership string
Name string
Email string
Groups []string
A few additional variables are also made available for your use:
Email.User part of the user's email address before the `@`
Email.Domain part of the user's email address after the `@`
JWT the entire JSON Web Token payload
Note that the variables in the template syntax are in CamelCase
, while the keys in the JWT token are in snake_case
. So, you if you needed to reference device_ownership
in a header using the template syntax, use .DeviceOwnership
.