Skip to content

Commit

Permalink
Merge pull request #2477 from Cyb3r-Jak3/update-tunnels-config
Browse files Browse the repository at this point in the history
Update tunnel config
  • Loading branch information
jacobbednarz authored May 29, 2023
2 parents dee8fe7 + ed2e926 commit 80728be
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 213 deletions.
3 changes: 3 additions & 0 deletions .changelog/2477.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_tunnel_config: add support for origin config on ingress rule and access
```
66 changes: 66 additions & 0 deletions docs/resources/tunnel_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ resource "cloudflare_tunnel_config" "example_config" {
hostname = "foo"
path = "/bar"
service = "http://10.0.0.2:8080"
origin_request {
connect_timeout = "2m0s"
access {
required = true
team_name = "terraform"
aud_tag = ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]
}
}
}
ingress_rule {
service = "https://10.0.0.3:8081"
Expand Down Expand Up @@ -97,18 +105,66 @@ Required:
Optional:

- `hostname` (String) Hostname to match the incoming request with. If the hostname matches, the request will be sent to the service.
- `origin_request` (Block List, Max: 1) (see [below for nested schema](#nestedblock--config--ingress_rule--origin_request))
- `path` (String) Path of the incoming request. If the path matches, the request will be sent to the local service.

<a id="nestedblock--config--ingress_rule--origin_request"></a>
### Nested Schema for `config.ingress_rule.origin_request`

Optional:

- `access` (Block List, Max: 1) Access rules for the ingress service. (see [below for nested schema](#nestedblock--config--ingress_rule--origin_request--access))
- `bastion_mode` (Boolean) Runs as jump host.
- `ca_pool` (String) Path to the certificate authority (CA) for the certificate of your origin. This option should be used only if your certificate is not signed by Cloudflare. Defaults to `""`.
- `connect_timeout` (String) Timeout for establishing a new TCP connection to your origin server. This excludes the time taken to establish TLS, which is controlled by `tlsTimeout`. Defaults to `30s`.
- `disable_chunked_encoding` (Boolean) Disables chunked transfer encoding. Useful if you are running a Web Server Gateway Interface (WSGI) server. Defaults to `false`.
- `http2_origin` (Boolean) Enables HTTP/2 support for the origin connection. Defaults to `false`.
- `http_host_header` (String) Sets the HTTP Host header on requests sent to the local service. Defaults to `""`.
- `ip_rules` (Block Set) IP rules for the proxy service. (see [below for nested schema](#nestedblock--config--ingress_rule--origin_request--ip_rules))
- `keep_alive_connections` (Number) Maximum number of idle keepalive connections between Tunnel and your origin. This does not restrict the total number of concurrent connections. Defaults to `100`.
- `keep_alive_timeout` (String) Timeout after which an idle keepalive connection can be discarded. Defaults to `1m30s`.
- `no_happy_eyeballs` (Boolean) Disable the “happy eyeballs” algorithm for IPv4/IPv6 fallback if your local network has misconfigured one of the protocols. Defaults to `false`.
- `no_tls_verify` (Boolean) Disables TLS verification of the certificate presented by your origin. Will allow any certificate from the origin to be accepted. Defaults to `false`.
- `origin_server_name` (String) Hostname that cloudflared should expect from your origin server certificate. Defaults to `""`.
- `proxy_address` (String) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures the listen address for that proxy. Defaults to `127.0.0.1`.
- `proxy_port` (Number) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures the listen port for that proxy. If set to zero, an unused port will randomly be chosen. Defaults to `0`.
- `proxy_type` (String) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures what type of proxy will be started. Available values: `""`, `socks`. Defaults to `""`.
- `tcp_keep_alive` (String) The timeout after which a TCP keepalive packet is sent on a connection between Tunnel and the origin server. Defaults to `30s`.
- `tls_timeout` (String) Timeout for completing a TLS handshake to your origin server, if you have chosen to connect Tunnel to an HTTPS server. Defaults to `10s`.

<a id="nestedblock--config--ingress_rule--origin_request--access"></a>
### Nested Schema for `config.ingress_rule.origin_request.access`

Optional:

- `aud_tag` (Set of String) Audience tags of the access rule.
- `required` (Boolean) Whether the access rule is required.
- `team_name` (String) Name of the team to which the access rule applies.


<a id="nestedblock--config--ingress_rule--origin_request--ip_rules"></a>
### Nested Schema for `config.ingress_rule.origin_request.ip_rules`

Optional:

- `allow` (Boolean) Whether to allow the IP prefix.
- `ports` (List of Number) Ports to use within the IP rule.
- `prefix` (String) IP rule prefix.




<a id="nestedblock--config--origin_request"></a>
### Nested Schema for `config.origin_request`

Optional:

- `access` (Block List, Max: 1) Access rules for the ingress service. (see [below for nested schema](#nestedblock--config--origin_request--access))
- `bastion_mode` (Boolean) Runs as jump host.
- `ca_pool` (String) Path to the certificate authority (CA) for the certificate of your origin. This option should be used only if your certificate is not signed by Cloudflare. Defaults to `""`.
- `connect_timeout` (String) Timeout for establishing a new TCP connection to your origin server. This excludes the time taken to establish TLS, which is controlled by `tlsTimeout`. Defaults to `30s`.
- `disable_chunked_encoding` (Boolean) Disables chunked transfer encoding. Useful if you are running a Web Server Gateway Interface (WSGI) server. Defaults to `false`.
- `http2_origin` (Boolean) Enables HTTP/2 support for the origin connection. Defaults to `false`.
- `http_host_header` (String) Sets the HTTP Host header on requests sent to the local service. Defaults to `""`.
- `ip_rules` (Block Set) IP rules for the proxy service. (see [below for nested schema](#nestedblock--config--origin_request--ip_rules))
- `keep_alive_connections` (Number) Maximum number of idle keepalive connections between Tunnel and your origin. This does not restrict the total number of concurrent connections. Defaults to `100`.
Expand All @@ -122,6 +178,16 @@ Optional:
- `tcp_keep_alive` (String) The timeout after which a TCP keepalive packet is sent on a connection between Tunnel and the origin server. Defaults to `30s`.
- `tls_timeout` (String) Timeout for completing a TLS handshake to your origin server, if you have chosen to connect Tunnel to an HTTPS server. Defaults to `10s`.

<a id="nestedblock--config--origin_request--access"></a>
### Nested Schema for `config.origin_request.access`

Optional:

- `aud_tag` (Set of String) Audience tags of the access rule.
- `required` (Boolean) Whether the access rule is required.
- `team_name` (String) Name of the team to which the access rule applies.


<a id="nestedblock--config--origin_request--ip_rules"></a>
### Nested Schema for `config.origin_request.ip_rules`

Expand Down
8 changes: 8 additions & 0 deletions examples/resources/cloudflare_tunnel_config/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ resource "cloudflare_tunnel_config" "example_config" {
hostname = "foo"
path = "/bar"
service = "http://10.0.0.2:8080"
origin_request {
connect_timeout = "2m0s"
access {
required = true
team_name = "terraform"
aud_tag = ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]
}
}
}
ingress_rule {
service = "https://10.0.0.3:8081"
Expand Down
221 changes: 133 additions & 88 deletions internal/sdkv2provider/resource_cloudflare_tunnel_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,121 @@ func resourceCloudflareTunnelConfig() *schema.Resource {
}
}

func buildTunnelOriginRequest(originRequest map[string]interface{}) (originConfig cloudflare.OriginRequestConfig) {
if v, ok := originRequest["connect_timeout"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.ConnectTimeout = &timeout
}
if v, ok := originRequest["tls_timeout"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.TLSTimeout = &timeout
}
if v, ok := originRequest["tcp_keep_alive"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.TCPKeepAlive = &timeout
}
if v, ok := originRequest["no_happy_eyeballs"]; ok {
originConfig.NoHappyEyeballs = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["keep_alive_connections"]; ok {
originConfig.KeepAliveConnections = cloudflare.IntPtr(v.(int))
}
if v, ok := originRequest["keep_alive_timeout"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.KeepAliveTimeout = &timeout
}
if v, ok := originRequest["http_host_header"]; ok {
originConfig.HTTPHostHeader = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["origin_server_name"]; ok {
originConfig.OriginServerName = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["ca_pool"]; ok {
originConfig.CAPool = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["no_tls_verify"]; ok {
originConfig.NoTLSVerify = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["disable_chunked_encoding"]; ok {
originConfig.DisableChunkedEncoding = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["bastion_mode"]; ok {
originConfig.BastionMode = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["proxy_address"]; ok {
originConfig.ProxyAddress = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["proxy_port"]; ok {
originConfig.ProxyPort = cloudflare.UintPtr(uint(v.(int)))
}
if v, ok := originRequest["proxy_type"]; ok {
originConfig.ProxyType = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["http2_origin"]; ok {
originConfig.Http2Origin = cloudflare.BoolPtr(v.(bool))
}
var ipRules []cloudflare.IngressIPRule
if v, ok := originRequest["ip_rules"]; ok {
for _, ingressRule := range v.(*schema.Set).List() {
ingressRuleConfig := ingressRule.(map[string]interface{})
ipRule := cloudflare.IngressIPRule{
Prefix: cloudflare.StringPtr(ingressRuleConfig["prefix"].(string)),
Allow: ingressRuleConfig["allow"].(bool),
}
for _, value := range ingressRuleConfig["ports"].([]interface{}) {
ipRule.Ports = append(ipRule.Ports, value.(int))
}
ipRules = append(ipRules, ipRule)
}
}
originConfig.IPRules = ipRules
if v, ok := originRequest["access"]; ok {
if len(v.([]interface{})) != 0 {
accessConfig := v.([]interface{})[0].(map[string]interface{})
originConfig.Access = &cloudflare.AccessConfig{
Required: accessConfig["required"].(bool),
TeamName: accessConfig["team_name"].(string),
}
for _, value := range accessConfig["aud_tag"].(*schema.Set).List() {
originConfig.Access.AudTag = append(originConfig.Access.AudTag, value.(string))
}
}
}

return
}

func parseOriginRequest(originRequest cloudflare.OriginRequestConfig) (returnValue []map[string]interface{}) {
returnValue = append(returnValue, map[string]interface{}{
"connect_timeout": originRequest.ConnectTimeout.String(),
"tls_timeout": originRequest.TLSTimeout.String(),
"tcp_keep_alive": originRequest.TCPKeepAlive.String(),
"no_happy_eyeballs": originRequest.NoHappyEyeballs,
"keep_alive_connections": originRequest.KeepAliveConnections,
"keep_alive_timeout": originRequest.KeepAliveTimeout.String(),
"http_host_header": originRequest.HTTPHostHeader,
"origin_server_name": originRequest.OriginServerName,
"ca_pool": originRequest.CAPool,
"no_tls_verify": originRequest.NoTLSVerify,
"disable_chunked_encoding": originRequest.DisableChunkedEncoding,
"bastion_mode": originRequest.BastionMode,
"proxy_address": originRequest.ProxyAddress,
"proxy_port": originRequest.ProxyPort,
"proxy_type": originRequest.ProxyType,
"http2_origin": originRequest.Http2Origin,
})
var accessConfig []map[string]interface{}
if originRequest.Access != nil {
accessConfig = append(accessConfig, map[string]interface{}{
"required": originRequest.Access.Required,
"team_name": originRequest.Access.TeamName,
"aud_tag": originRequest.Access.AudTag,
})
}
returnValue[0]["access"] = accessConfig
return
}

func buildTunnelConfig(d *schema.ResourceData) cloudflare.TunnelConfiguration {
warpRouting := cloudflare.WarpRoutingConfig{}
if item, ok := d.GetOk("config.0.warp_routing"); ok {
Expand All @@ -43,72 +158,7 @@ func buildTunnelConfig(d *schema.ResourceData) cloudflare.TunnelConfiguration {

originConfig := cloudflare.OriginRequestConfig{}
if item, ok := d.GetOk("config.0.origin_request"); ok {
originRequest := item.([]interface{})[0].(map[string]interface{})
if v, ok := originRequest["connect_timeout"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.ConnectTimeout = &timeout
}
if v, ok := originRequest["tls_timeout"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.TLSTimeout = &timeout
}
if v, ok := originRequest["tcp_keep_alive"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.TCPKeepAlive = &timeout
}
if v, ok := originRequest["no_happy_eyeballs"]; ok {
originConfig.NoHappyEyeballs = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["keep_alive_connections"]; ok {
originConfig.KeepAliveConnections = cloudflare.IntPtr(v.(int))
}
if v, ok := originRequest["keep_alive_timeout"]; ok {
timeout, _ := time.ParseDuration(v.(string))
originConfig.KeepAliveTimeout = &timeout
}
if v, ok := originRequest["http_host_header"]; ok {
originConfig.HTTPHostHeader = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["origin_server_name"]; ok {
originConfig.OriginServerName = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["ca_pool"]; ok {
originConfig.CAPool = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["no_tls_verify"]; ok {
originConfig.NoTLSVerify = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["disable_chunked_encoding"]; ok {
originConfig.DisableChunkedEncoding = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["bastion_mode"]; ok {
originConfig.BastionMode = cloudflare.BoolPtr(v.(bool))
}
if v, ok := originRequest["proxy_address"]; ok {
originConfig.ProxyAddress = cloudflare.StringPtr(v.(string))
}
if v, ok := originRequest["proxy_port"]; ok {
originConfig.ProxyPort = cloudflare.UintPtr(uint(v.(int)))
}
if v, ok := originRequest["proxy_type"]; ok {
originConfig.ProxyType = cloudflare.StringPtr(v.(string))
}

var ipRules []cloudflare.IngressIPRule
if v, ok := originRequest["ip_rules"]; ok {
for _, ingressRule := range v.(*schema.Set).List() {
ingressRuleConfig := ingressRule.(map[string]interface{})
ipRule := cloudflare.IngressIPRule{
Prefix: cloudflare.StringPtr(ingressRuleConfig["prefix"].(string)),
Allow: ingressRuleConfig["allow"].(bool),
}
for _, value := range ingressRuleConfig["ports"].([]interface{}) {
ipRule.Ports = append(ipRule.Ports, value.(int))
}
ipRules = append(ipRules, ipRule)
}
}
originConfig.IPRules = ipRules
originConfig = buildTunnelOriginRequest(item.([]interface{})[0].(map[string]interface{}))
}

var ingressRules []cloudflare.UnvalidatedIngressRule
Expand All @@ -119,6 +169,12 @@ func buildTunnelConfig(d *schema.ResourceData) cloudflare.TunnelConfiguration {
Hostname: ingressRuleConfig["hostname"].(string),
Path: ingressRuleConfig["path"].(string),
}
if v, ok := ingressRuleConfig["origin_request"]; ok {
if len(v.([]interface{})) != 0 {
ingressOriginConfig := buildTunnelOriginRequest(v.([]interface{})[0].(map[string]interface{}))
ingressRule.OriginRequest = &ingressOriginConfig
}
}
ingressRules = append(ingressRules, ingressRule)
}

Expand Down Expand Up @@ -154,23 +210,7 @@ func resourceCloudflareTunnelConfigRead(ctx context.Context, d *schema.ResourceD
var originRequestMap []map[string]interface{}
emptyOriginRequest := cloudflare.OriginRequestConfig{}
if !reflect.DeepEqual(config.OriginRequest, emptyOriginRequest) {
originRequestMap = append(originRequestMap, map[string]interface{}{
"connect_timeout": config.OriginRequest.ConnectTimeout.String(),
"tls_timeout": config.OriginRequest.TLSTimeout.String(),
"tcp_keep_alive": config.OriginRequest.TCPKeepAlive.String(),
"no_happy_eyeballs": cloudflare.Bool(config.OriginRequest.NoHappyEyeballs),
"keep_alive_connections": cloudflare.Int(config.OriginRequest.KeepAliveConnections),
"keep_alive_timeout": config.OriginRequest.KeepAliveTimeout.String(),
"http_host_header": cloudflare.String(config.OriginRequest.HTTPHostHeader),
"origin_server_name": cloudflare.String(config.OriginRequest.OriginServerName),
"ca_pool": cloudflare.String(config.OriginRequest.CAPool),
"no_tls_verify": cloudflare.Bool(config.OriginRequest.NoTLSVerify),
"disable_chunked_encoding": cloudflare.Bool(config.OriginRequest.DisableChunkedEncoding),
"bastion_mode": cloudflare.Bool(config.OriginRequest.BastionMode),
"proxy_address": cloudflare.String(config.OriginRequest.ProxyAddress),
"proxy_port": int(cloudflare.Uint(config.OriginRequest.ProxyPort)),
"proxy_type": cloudflare.String(config.OriginRequest.ProxyType),
})
originRequestMap = parseOriginRequest(config.OriginRequest)
var ipRules []map[string]interface{}
for _, ipRule := range config.OriginRequest.IPRules {
ipRules = append(ipRules, map[string]interface{}{
Expand All @@ -184,11 +224,16 @@ func resourceCloudflareTunnelConfigRead(ctx context.Context, d *schema.ResourceD

var ingressRules []map[string]interface{}
for _, ingressRule := range config.Ingress {
ingressRules = append(ingressRules, map[string]interface{}{
"service": ingressRule.Service,
"hostname": ingressRule.Hostname,
"path": ingressRule.Path,
})
var rule = make(map[string]interface{})
rule["service"] = ingressRule.Service
rule["hostname"] = ingressRule.Hostname
rule["path"] = ingressRule.Path
var ingressOriginRequestMap []map[string]interface{}
if ingressRule.OriginRequest != nil {
ingressOriginRequestMap = parseOriginRequest(*ingressRule.OriginRequest)
rule["origin_request"] = ingressOriginRequestMap
}
ingressRules = append(ingressRules, rule)
}
configMap = append(configMap, map[string]interface{}{
"warp_routing": warpConfigMap,
Expand Down
Loading

0 comments on commit 80728be

Please sign in to comment.