Skip to content

Commit

Permalink
discovery: support multiple TXT records
Browse files Browse the repository at this point in the history
  • Loading branch information
evenh committed Aug 1, 2024
1 parent bfdf93b commit 5d10776
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 27 deletions.
39 changes: 23 additions & 16 deletions pkg/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@ import (
"github.com/kartverket/skipctl/pkg/constants"
)

var resolver = net.DefaultResolver
var (
resolver = net.DefaultResolver
b64 = base64.StdEncoding
)

type APIServer struct {
Name string `json:"name"`
Addr string `json:"addr"`
}

// DiscoverAPIServers will try to do a TXT lookup for a given DNS name. If found it will
// attempt a unmarshaL(base64_decode(TXT_RECORD_VALUE)) (pseudo code) into a list of APIServer
// attempt a unmarshal(base64_decode(TXT_RECORD_VALUE)) (pseudo code) into a list of APIServer
// structs.
//
// One TXT record per server.
func DiscoverAPIServers(dnsKey string) ([]APIServer, error) {
ctx, cancel := context.WithTimeout(context.Background(), constants.DNSDiscoverTimeout)
defer cancel()
Expand All @@ -29,21 +34,23 @@ func DiscoverAPIServers(dnsKey string) ([]APIServer, error) {
return nil, fmt.Errorf("failed discover available API servers: %w", err)
}

if len(records) > 1 {
return nil, fmt.Errorf("found more than one TXT record with the same name: %s", dnsKey)
}

// Wrap the outer layer
decodedBytes, err := base64.StdEncoding.DecodeString(records[0])
if err != nil {
return nil, fmt.Errorf("failed base64 decoding TXT record: %w", err)
}

// Decode JSON into a usable structure
var apiServers []APIServer
err = json.Unmarshal(decodedBytes, &apiServers)
if err != nil {
return nil, fmt.Errorf("failed unmarshalling TXT record: %w", err)

for _, txtRecord := range records {
// Wrap the outer layer
decodedBytes, decodeErr := b64.DecodeString(txtRecord)
if decodeErr != nil {
return nil, fmt.Errorf("failed base64 decoding TXT record: %w", decodeErr)
}

// Decode JSON into a usable structure
var apiServer APIServer
err = json.Unmarshal(decodedBytes, &apiServer)
if err != nil {
return nil, fmt.Errorf("failed unmarshalling TXT record: %w", err)
}

apiServers = append(apiServers, apiServer)
}

return apiServers, nil
Expand Down
21 changes: 10 additions & 11 deletions server.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Running a skipctl server

1. `skipctl --output=json serve` with priviliges to do raw ICMP sockets.
1. `skipctl --output=json serve` with privileges to do raw ICMP sockets (CAP_NET_RAW or root).
2. Put it behind a reverse proxy terminating TLS (e.g. an Istio gateway or nginx)
3. Update DNS to make it available via service discovery from the clients

Expand All @@ -15,28 +15,27 @@ dig TXT _skipctl.example.com
; <<>> DiG 9.10.6 <<>> TXT _skipctl.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44391
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32281
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;_skipctl.example.com. IN TXT
;_skipctl.example.com. IN TXT
;; ANSWER SECTION:
_skipctl.example.com. 60 IN TXT "WwogICAgewogICAgICAgICJuYW1lIjogImF0a3YzLWV2ZW5oIiwKICAgICAgICAiYWRkciI6ICJsb2NhbGhvc3QuZXZlbmgubmV0OjQ0MyIKICAgIH0KXQ=="
_skipctl.example.com. 299 IN TXT "eyJhZGRyIjoiYXBpc2VydmVyMS5leGFtcGxlLmNvbTo0NDMiLCJuYW1lIjoibXlBcGlTZXJ2ZXIifQ=="
_skipctl.example.com. 299 IN TXT "eyJhZGRyIjoiYXBpc2VydmVyMi5leGFtcGxlLmNvbTo0NDMiLCJuYW1lIjoiYW5vdGhlckFwaVNlcnZlciJ9"
[…]
```
The response is a base64 encoded JSON structure in the following form:
```json
[
{
{
"name": "myApiServer",
"addr": "api-server-1.internal.example.com:443"
}
]
}
```
In order to make more API servers available, this array must be expanded, base64 encoded and the TXT record must be updated. Be sure to validate both JSON and base64 encoding before updating the record.
In order to make more API servers available, a new TXT record under the same domain must be provisioned. Each entry must be base64 encoded and the new TXT record must be added. Be sure to validate both JSON and base64 encoding before updating records.

0 comments on commit 5d10776

Please sign in to comment.