Skip to content

Commit

Permalink
add the provider for the tencent cloud.
Browse files Browse the repository at this point in the history
Signed-off-by: misakazhou <[email protected]>
  • Loading branch information
Hyzhou committed Aug 25, 2022
1 parent d44b239 commit 10fad34
Show file tree
Hide file tree
Showing 17 changed files with 1,966 additions and 1 deletion.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ ExternalDNS allows you to keep selected zones (via `--domain-filter`) synchroniz
* [Gandi](https://www.gandi.net)
* [ANS Group SafeDNS](https://portal.ans.co.uk/safedns/)
* [IBM Cloud DNS](https://www.ibm.com/cloud/dns)
* [TencentCloud PrivateDNS](https://cloud.tencent.com/product/privatedns)
* [TencentCloud DNSPod](https://cloud.tencent.com/product/cns)

From this release, ExternalDNS can become aware of the records it is managing (enabled via `--registry=txt`), therefore ExternalDNS can safely manage non-empty hosted zones. We strongly encourage you to use `v0.5` (or greater) with `--registry=txt` enabled and `--txt-owner-id` set to a unique value that doesn't change for the lifetime of your cluster. You might also want to run ExternalDNS in a dry run mode (`--dry-run` flag) to see the changes to be submitted to your DNS Provider API.

Expand Down Expand Up @@ -115,6 +117,7 @@ The following table clarifies the current status of the providers according to t
| Gandi | Alpha | @packi |
| SafeDNS | Alpha | @assureddt |
| IBMCloud | Alpha | @hughhuangzh |
| TencentCloud | Alpha | @Hyzhou |

## Kubernetes version compatibility

Expand Down Expand Up @@ -183,6 +186,7 @@ The following tutorials are provided:
* [SafeDNS](docs/tutorials/UKFast_SafeDNS.md)
* [IBM Cloud](docs/tutorials/ibmcloud.md)
* [Nodes as source](docs/tutorials/nodes.md)
* [TencentCloud](docs/tutorials/tencentcloud.md)

### Running Locally

Expand Down
208 changes: 208 additions & 0 deletions docs/tutorials/tencentcloud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Setting up ExternalDNS for Tencent Cloud

## External Dns Version
* Make sure to use **>=1.7.2** version of ExternalDNS for this tutorial

## Set up PrivateDns or DNSPod

Tencent Cloud DNSPod Service is the domain name resolution and management service for public access.
Tencent Cloud PrivateDNS Service is the domain name resolution and management service for VPC internal access.

* If you want to use internal dns service in Tencent Cloud.
1. Set up the args `--tencent-cloud-zone-type=private`
2. Create a DNS domain in PrivateDNS console. DNS domain which will contain the managed DNS records.

* If you want to use public dns service in Tencent Cloud.
1. Set up the args `--tencent-cloud-zone-type=public`
2. Create a Domain in DnsPod console. DNS domain which will contain the managed DNS records.

## Set up CAM for API Key

In Tencent CAM Console. you may get the secretId and secretKey pair. make sure the key pair has those Policy.
```json
{
"version": "2.0",
"statement": [
{
"effect": "allow",
"action": [
"dnspod:ModifyRecord",
"dnspod:DeleteRecord",
"dnspod:CreateRecord",
"dnspod:DescribeRecordList",
"dnspod:DescribeDomainList"
],
"resource": [
"*"
]
},
{
"effect": "allow",
"action": [
"privatedns:DescribePrivateZoneList",
"privatedns:DescribePrivateZoneRecordList",
"privatedns:CreatePrivateZoneRecord",
"privatedns:DeletePrivateZoneRecord",
"privatedns:ModifyPrivateZoneRecord"
],
"resource": [
"*"
]
}
]
}
```

# Deploy ExternalDNS

## Manifest (for clusters with RBAC enabled)

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
---
apiVersion: v1
kind: ConfigMap
metadata:
name: external-dns
data:
tencent-cloud.json: |
{
"regionId": "ap-shanghai",
"secretId": "******",
"secretKey": "******",
"vpcId": "vpc-******"
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
containers:
- args:
- --source=service
- --source=ingress
- --domain-filter=external-dns-test.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=tencentcloud
- --policy=sync # set `upsert-only` would prevent ExternalDNS from deleting any records
- --tencent-cloud-zone-type=private # only look at private hosted zones. set `public` to use the public dns service.
- --tencent-cloud-config-file=/etc/kubernetes/tencent-cloud.json
image: k8s.gcr.io/external-dns/external-dns:v1.7.2
imagePullPolicy: Always
name: external-dns
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/kubernetes
name: config-volume
readOnly: true
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: external-dns
serviceAccountName: external-dns
terminationGracePeriodSeconds: 30
volumes:
- configMap:
defaultMode: 420
items:
- key: tencent-cloud.json
path: tencent-cloud.json
name: external-dns
name: config-volume
```
# Example
## Service
```yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
annotations:
external-dns.alpha.kubernetes.io/hostname: nginx.external-dns-test.com
external-dns.alpha.kubernetes.io/internal-hostname: nginx-internal.external-dns-test.com
external-dns.alpha.kubernetes.io/ttl: "600"
spec:
type: LoadBalancer
ports:
- port: 80
name: http
targetPort: 80
selector:
app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
name: http
```
`nginx.external-dns-test.com` will record to the Loadbalancer VIP.
`nginx-internal.external-dns-test.com` will record to the ClusterIP.
all of the DNS Record ttl will be 600.

# Attention

This makes ExternalDNS safe for running in environments where there are other records managed via other means.

3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ require (
github.com/smartystreets/gunit v1.3.4 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.344
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.344
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.344
github.com/terra-farm/udnssdk v1.3.5 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.2 // indirect
go.mongodb.org/mongo-driver v1.5.1 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,12 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.344 h1:QhPDamT0YL04UaoteA9AEHnE/sklwYr+VSKd/pPQ6r8=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.344/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.344 h1:pdwJ6T3iEjP5nB9Mgi4y/OBO8XNtkGN2/+mjGZ8yCbw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.344/go.mod h1:CuOaLxOQr477GhMWAQPYQFUJrsZbW+ZqkAgP2uHDZXg=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.344 h1:q4r39zJkMyHvrORok48IOJz/nJ235dIkHStA9LZYwgw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.344/go.mod h1:En+pdagcHkAASorHT1l8R6tUtieRNNxaQ7nfyqWPefk=
github.com/terra-farm/udnssdk v1.3.5 h1:MNR3adfuuEK/l04+jzo8WW/0fnorY+nW515qb3vEr6I=
github.com/terra-farm/udnssdk v1.3.5/go.mod h1:8RnM56yZTR7mYyUIvrDgXzdRaEyFIzqdEi7+um26Sv8=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
Expand Down
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import (
"sigs.k8s.io/external-dns/provider/rfc2136"
"sigs.k8s.io/external-dns/provider/safedns"
"sigs.k8s.io/external-dns/provider/scaleway"
"sigs.k8s.io/external-dns/provider/tencentcloud"
"sigs.k8s.io/external-dns/provider/transip"
"sigs.k8s.io/external-dns/provider/ultradns"
"sigs.k8s.io/external-dns/provider/vinyldns"
Expand Down Expand Up @@ -334,6 +335,8 @@ func main() {
p, err = ibmcloud.NewIBMCloudProvider(cfg.IBMCloudConfigFile, domainFilter, zoneIDFilter, endpointsSource, cfg.IBMCloudProxied, cfg.DryRun)
case "safedns":
p, err = safedns.NewSafeDNSProvider(domainFilter, cfg.DryRun)
case "tencentcloud":
p, err = tencentcloud.NewTencentCloudProvider(domainFilter, zoneIDFilter, cfg.TencentCloudConfigFile, cfg.TencentCloudZoneType, cfg.DryRun)
default:
log.Fatalf("unknown dns provider: %s", cfg.Provider)
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ type Config struct {
OCPRouterName string
IBMCloudProxied bool
IBMCloudConfigFile string
TencentCloudConfigFile string
TencentCloudZoneType string
}

var defaultConfig = &Config{
Expand Down Expand Up @@ -223,6 +225,7 @@ var defaultConfig = &Config{
GoogleBatchChangeInterval: time.Second,
GoogleZoneVisibility: "",
DomainFilter: []string{},
ZoneIDFilter: []string{},
ExcludeDomains: []string{},
RegexDomainFilter: regexp.MustCompile(""),
RegexDomainExclusion: regexp.MustCompile(""),
Expand Down Expand Up @@ -326,6 +329,8 @@ var defaultConfig = &Config{
GoDaddyOTE: false,
IBMCloudProxied: false,
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
TencentCloudZoneType: "",
}

// NewConfig returns new Config object
Expand Down Expand Up @@ -415,7 +420,7 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets)

// Flags related to providers
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, ibmcloud, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns, gandi, safedns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "ibmcloud", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy", "bluecat", "gandi", "safedns")
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, ibmcloud, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns, gandi, safedns, tencentcloud)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "ibmcloud", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy", "bluecat", "gandi", "safedns", "tencentcloud")
app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains)
app.Flag("regex-domain-filter", "Limit possible domains and target zones by a Regex filter; Overrides domain-filter (optional)").Default(defaultConfig.RegexDomainFilter.String()).RegexpVar(&cfg.RegexDomainFilter)
Expand Down Expand Up @@ -443,6 +448,8 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("azure-resource-group", "When using the Azure provider, override the Azure resource group to use (required when --provider=azure-private-dns)").Default(defaultConfig.AzureResourceGroup).StringVar(&cfg.AzureResourceGroup)
app.Flag("azure-subscription-id", "When using the Azure provider, specify the Azure configuration file (required when --provider=azure-private-dns)").Default(defaultConfig.AzureSubscriptionID).StringVar(&cfg.AzureSubscriptionID)
app.Flag("azure-user-assigned-identity-client-id", "When using the Azure provider, override the client id of user assigned identity in config file (optional)").Default("").StringVar(&cfg.AzureUserAssignedIdentityClientID)
app.Flag("tencent-cloud-config-file", "When using the Tencent Cloud provider, specify the Tencent Cloud configuration file (required when --provider=tencentcloud").Default(defaultConfig.TencentCloudConfigFile).StringVar(&cfg.TencentCloudConfigFile)
app.Flag("tencent-cloud-zone-type", "When using the Tencent Cloud provider, filter for zones with visibility (optional, options: public, private)").Default(defaultConfig.TencentCloudZoneType).EnumVar(&cfg.TencentCloudZoneType, "", "public", "private")

// Flags related to BlueCat provider
app.Flag("bluecat-dns-configuration", "When using the Bluecat provider, specify the Bluecat DNS configuration string (optional when --provider=bluecat)").Default("").StringVar(&cfg.BluecatDNSConfiguration)
Expand Down
8 changes: 8 additions & 0 deletions pkg/apis/externaldns/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ var (
OCPRouterName: "default",
IBMCloudProxied: false,
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
TencentCloudZoneType: "",
}

overriddenConfig = &Config{
Expand Down Expand Up @@ -235,6 +237,8 @@ var (
RFC2136BatchChangeSize: 100,
IBMCloudProxied: true,
IBMCloudConfigFile: "ibmcloud.json",
TencentCloudConfigFile: "tencent-cloud.json",
TencentCloudZoneType: "private",
}
)

Expand Down Expand Up @@ -373,6 +377,8 @@ func TestParseFlags(t *testing.T) {
"--rfc2136-batch-change-size=100",
"--ibmcloud-proxied",
"--ibmcloud-config-file=ibmcloud.json",
"--tencent-cloud-config-file=tencent-cloud.json",
"--tencent-cloud-zone-type=private",
},
envVars: map[string]string{},
expected: overriddenConfig,
Expand Down Expand Up @@ -486,6 +492,8 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE": "100",
"EXTERNAL_DNS_IBMCLOUD_PROXIED": "1",
"EXTERNAL_DNS_IBMCLOUD_CONFIG_FILE": "ibmcloud.json",
"EXTERNAL_DNS_TENCENT_CLOUD_CONFIG_FILE": "tencent-cloud.json",
"EXTERNAL_DNS_TENCENT_CLOUD_ZONE_TYPE": "private",
},
expected: overriddenConfig,
},
Expand Down
44 changes: 44 additions & 0 deletions provider/tencentcloud/cloudapi/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cloudapi

import (
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
)

type Action struct {
Service string `json:"service"`
Name string `json:"name"`
ReadOnly bool `json:"readOnly"`
}

var (
/* PrivateDNS */
CreatePrivateZoneRecord = Action{Service: "PrivateDns", Name: "CreatePrivateZoneRecord", ReadOnly: false}
DeletePrivateZoneRecord = Action{Service: "PrivateDns", Name: "DeletePrivateZoneRecord", ReadOnly: false}
ModifyPrivateZoneRecord = Action{Service: "PrivateDns", Name: "ModifyPrivateZoneRecord", ReadOnly: false}
DescribePrivateZoneList = Action{Service: "PrivateDns", Name: "DescribePrivateZoneList", ReadOnly: true}
DescribePrivateZoneRecordList = Action{Service: "PrivateDns", Name: "DescribePrivateZoneRecordList", ReadOnly: true}

/* DNSPod */
DescribeDomainList = Action{Service: "DnsPod", Name: "DescribeDomainList", ReadOnly: true}
DescribeRecordList = Action{Service: "DnsPod", Name: "DescribeRecordList", ReadOnly: true}
CreateRecord = Action{Service: "DnsPod", Name: "CreateRecord", ReadOnly: false}
DeleteRecord = Action{Service: "DnsPod", Name: "DeleteRecord", ReadOnly: false}
ModifyRecord = Action{Service: "DnsPod", Name: "ModifyRecord", ReadOnly: false}
)

type TencentAPIService interface {
// PrivateDNS
CreatePrivateZoneRecord(request *privatedns.CreatePrivateZoneRecordRequest) (response *privatedns.CreatePrivateZoneRecordResponse, err error)
DeletePrivateZoneRecord(request *privatedns.DeletePrivateZoneRecordRequest) (response *privatedns.DeletePrivateZoneRecordResponse, err error)
ModifyPrivateZoneRecord(request *privatedns.ModifyPrivateZoneRecordRequest) (response *privatedns.ModifyPrivateZoneRecordResponse, err error)
DescribePrivateZoneList(request *privatedns.DescribePrivateZoneListRequest) (response *privatedns.DescribePrivateZoneListResponse, err error)
DescribePrivateZoneRecordList(request *privatedns.DescribePrivateZoneRecordListRequest) (response *privatedns.DescribePrivateZoneRecordListResponse, err error)

// DNSPod
DescribeDomainList(request *dnspod.DescribeDomainListRequest) (response *dnspod.DescribeDomainListResponse, err error)
DescribeRecordList(request *dnspod.DescribeRecordListRequest) (response *dnspod.DescribeRecordListResponse, err error)
CreateRecord(request *dnspod.CreateRecordRequest) (response *dnspod.CreateRecordResponse, err error)
DeleteRecord(request *dnspod.DeleteRecordRequest) (response *dnspod.DeleteRecordResponse, err error)
ModifyRecord(request *dnspod.ModifyRecordRequest) (response *dnspod.ModifyRecordResponse, err error)
}
Loading

0 comments on commit 10fad34

Please sign in to comment.