Commit Graph

689 Commits

Author SHA1 Message Date
Brian Cunnie
63d306b750 k8s: DNS server is deployed on AWS 2021-04-04 16:18:39 -07:00
Brian Cunnie
e27d536947 README: acknowledge JetBrains _et alii_ 2021-03-16 08:06:02 -07:00
Brian Cunnie
406b81c340 Dockerfile, Binaries include ARM (arm64 / aarch64)
Dockerfile:
- We use `CMD` instead of `ENTRYPOINT` because it's marginally easier
  to debug.
- We include 64-bit ARM, but not 32-bit
- We had to re-order the steps so that `apk add bind-tools` came
  before copying the binary; that fixed a bug where the
  `sslip.io-dns-server` wasn't on the ARM container filesystem (but it
  was on the amd64 filesystem 🤔)

Binaries
- We now build arm64 (GOARCH) versions of FreeBSD, Linux, and macOS
  (GOOS), but not Windows. It apparently doesn't have arm64 support yet.
2021-03-08 20:29:31 -08:00
Brian Cunnie
5cd770bbbd k8s sslip.io.yml: Deployment + NodePort Service 2021-02-28 21:30:47 -08:00
Brian Cunnie
947b47c8c5 Dockerfile: sslip.io has dig to allow probes
It increases the size of the image from 8MB to 26MB, but in the grand
scheme of things that's not much space.
2021-02-28 19:57:38 -08:00
Brian Cunnie
4ed10c4408 Dockerfile needs ip, ifconfig, tcpdump...
...to troubleshoot k8s even more.
2021-02-22 21:56:25 -08:00
Brian Cunnie
56248bc87a Dockerfile needs ping...
...so that I can troubleshoot my cluster
2021-02-22 20:47:01 -08:00
Brian Cunnie
e9eea2334c Website: plea to report Let's Encrypt rate-limits
We want people to report rate-limiting so we know to request an
increase.

[#6]
2021-02-12 19:11:42 -08:00
Brian Cunnie
74aed2f5b1 HTML: better wording for wildcard subdomains
The previous version wasn't clear.
2021-02-10 13:12:55 -08:00
Brian Cunnie
e14d7f0571 Website Documentation: Expand TLS options
- Use HTTP-01 challenge for run-of-the-mill certificates
- White label domains can acquire their own wildcard certificates
- VMware employees have access to *.sslip.io wildcard
- Use DNS-01 challenge for *.w-x-y-z.sslip.io wildcards
2021-02-09 08:22:57 -08:00
Brian Cunnie
3fc089b7a7 wildcard-dns-http-server: better error-checking
- when DNS gets a permission error, it helpfully suggests using `sudo`
- when DNS can't bind to `INADDR_ANY`, it's probably because it's Fedora
running `systemd.resolved` on port 53 of 127.0.0.53, so we try to bind
to each address individually.
- we don't implement similar checks for the HTTP server:
  - if it's a permission problem, the DNS server has already warned the
  user.
  - if it's a binding problem, the user is probably running an HTTP
  server bound to `INADDR_ANY`, so we might as well exit.
- we ported this code from main `sslip.io` DNS server.
2021-02-09 06:49:00 -08:00
Brian Cunnie
7ad3f4a22f Log better messages for DNS/HTTP server
The `wildcard-dns-http-server` didn't clearly differentiate the DNS
subsystem log messages from the HTTP subsystem log messages. We now
prepend "DNS:" and "HTTP:" depending the source of the message.
2021-02-08 20:00:27 -08:00
Brian Cunnie
fe3d81f194 Wildcard instructions: formatting, typos 2021-02-08 09:10:58 -08:00
Brian Cunnie
73a735bf37 Wildcard instructions: incorporate Norman's suggestions
Drive-by: update version numbers in `DEVELOPER.md`.
2021-02-06 14:02:21 -08:00
Brian Cunnie
ff35a2c1d1 Dockerfile: cunnie/sslip.io-dns-server → 2.1.2 2021-01-30 20:02:40 -08:00
Brian Cunnie
d2ed920d20 Bump version number on download link on web page 2021-01-30 20:00:19 -08:00
Brian Cunnie
041744312f BOSH release: 2.1.2: case-insensitive custom records matching 2.1.2 2021-01-30 19:37:45 -08:00
Brian Cunnie
1614f574bc 🐞 Ignore case when comparing customized records
This fixes an error when procuring Let's Encrypt certs using HTTP-01
challenge--my server didn't recognize, when queried with `SsLiP.iO`,
that it's the same as `sslip.io`, and so it doesn't reply with the
correct A/AAAA records.

fixes:
```
sudo /usr/local/bin/certbot renew
  No valid IP addresses found for sslip.io
```

log messages from `/var/vcap/sys/log/sslip.io-dns-server/sslip.io-dns-server.stderr.log`:
```
2021/01/30 21:45:49 3.122.55.230.22713 TypeA SsliP.IO. ? nil, SOA SsliP.IO. briancunnie.gmail.com. 2021011400 900 900 1800 300
2021/01/30 21:45:49 54.187.227.254.16621 TypeAAAA SslIP.io. ? nil, SOA SslIP.io. briancunnie.gmail.com. 2021011400 900 900 1800 300
```
2021-01-30 13:47:50 -08:00
Brian Cunnie
64df830d91 Use Go 1.13's errors.As() wherever possible
Now I know how to use a `syscall.Errno` with `errors.As()`
2021-01-30 12:37:52 -08:00
Brian Cunnie
115973bc12 Binding to port 53: better messaging
The bulk of this commit is to address problems under Linux:

- The user needs to be root to bind to port 53 (or have the
`CAP_NET_BIND_SERVICE` capability), so if we have a permissions-problem,
we say, "try `sudo`".

- If we can't bind to `INADDR_ANY`, and we probably can't because
"`systemd-resolved` provides a local DNS stub listener on IP address
127.0.0.53" on port 53, which prevents us from binding, we fallback
to attempting to bind to every available address individually.

This commit bloats `main.go`, which I have mixed feelings about because
it's untested.
2021-01-25 06:36:07 -08:00
Brian Cunnie
0d5886120a Give users a hint when permissions fail
addresses:
```
listen udp :53: bind: permission denied
```
2021-01-23 12:41:39 -08:00
Brian Cunnie
c349b45ea6 Docs: Securing a wildcard cert from Let's Encrypt
We are pleased to announce that these instructions finally work.

[#6]
2021-01-20 16:45:01 -08:00
Brian Cunnie
0be7a8c7e6 Dockerfile: cunnie/sslip.io-dns-server → 2.1.1 2021-01-20 16:03:57 -08:00
Brian Cunnie
5429c71c87 BOSH release: 2.1.1: case-insensitive _acme-challenge matching 2.1.1 2021-01-20 15:51:00 -08:00
Brian Cunnie
1a9279ecc1 🐞 _acme-challenge. comparisons are case-insensitive
Our DNS-01 challenges were failing because we weren't prepared for
mixed-case queries. Now we properly recognize them.

```
2021/01/20 20:15:40 3.123.253.205.45368 TypeTXT _ACMe-cHalLeNGE.34-83-219-164.sSlip.Io. ? nil, SOA _ACMe-cHalLeNGE.34-83-219-164.sSlip.Io. briancunnie.gmail.com. 2021011400 900 900 1800 300
```
```
2021/01/20 20:15:40 18.219.85.19.35164 TypeTXT _acMe-chaLlENGe.34-83-219-164.ssliP.Io. ? nil, SOA _acMe-chaLlENGe.34-83-219-164.ssliP.Io. briancunnie.gmail.com. 2021011400 900 900 1800 300
```
```
2021/01/20 20:15:40 66.133.109.36.11107 TypeTXT _aCme-chaLleNGe.34-83-219-164.sSLip.Io. ? nil, SOA _aCme-chaLleNGe.34-83-219-164.sSLip.Io. briancunnie.gmail.com. 2021011400 900 900 1800 300
```
2021-01-20 13:00:42 -08:00
Brian Cunnie
a3de35fa45 Dockerfile: cunnie/sslip.io-dns-server → 2.1.0 2021-01-20 11:59:42 -08:00
Brian Cunnie
3025c8186d BOSH release: 2.1.0: moar _acme-challenge delegation 2.1.0 2021-01-20 08:54:00 -08:00
Brian Cunnie
f797605bba Delegate ALL "_acme-challenge." queries
The purpose of this commit is to enable Let's Encrypt DNS-01 challenges
for wildcard certificates.

To accomplish that, we'd like to delegate queries for ALL types (e.g.
NS, SOA, A, AAAA) to the IP address of that server. For example, any
query for `_acme-challenge.52-0-56-137.sslip.io` would be delegated to
the DNS server `52-0-56-137.sslip.io` (whose IP address 52.0.56.137
would be supplied as well).

Thanks @NormanR !

On a personal note, I feel the code is getting bloated again. Also, I'm
inconsistent with my parameters: `NSResponse()`, for example, has
arguments which it mutates (`response`), and which are returned
(`logMessage`). This offends my esthetics.

[#6]
2021-01-20 08:23:53 -08:00
Brian Cunnie
4816854d3f Response queries include NS IP addrs in Additionals
When querying for NS (name server) records, the responses include an
"Additionals" section which lists the IP addresses of the name server.
This is a courtesy & an optimization: by sending the IP address, we
avoid the client sending a second query for the IP address of the
nameserver.

With this change, the following command...

```
dig @ns-aws.nono.io sslip.io ns
```

...will yield these additional records:

```diff
+;; ADDITIONAL SECTION:
+ns-aws.nono.io.                604800  IN      A       52.0.56.137
+ns-azure.nono.io.              604800  IN      A       52.187.42.158
+ns-gce.nono.io.                604800  IN      A       104.155.144.4
```
2021-01-20 06:39:02 -08:00
Brian Cunnie
9691e1326d 🐞 Tests: Fix out-of-order matching on Linux
Our CI is failing, and it appears that the `Eventually` pointer is moved
ahead by one of the tests, skipping over the line that another test is
waiting for.

To fix, rather than relying on a pointer, we compare the entire contents
of the DNS server's stderr output. We also remove the `$` anchor from
the regex which was causing it to fail.

fixes <https://ci.nono.io/teams/main/pipelines/sslip.io/jobs/unit/builds/149>:
```
  Got stuck at:
      2021/01/19 15:34:28 127.0.0.1.60973 TypeNS example.com. ? ns-aws.nono.io., ns-azure.nono.io., ns-gce.nono.io.
      2021/01/19 15:34:28 127.0.0.1.46683 TypeMX sslip.io. ? 10 mail.protonmail.ch., 20 mailsec.protonmail.ch.

  Waiting for:
      TypeNS example.com. \? ns-aws.nono.io., ns-azure.nono.io., ns-gce.nono.io.\n$
```
2021-01-19 08:30:02 -08:00
Brian Cunnie
c44b8e6d94 🐞 ;; Warning: ID mismatch: expected ID x, got y
When I ran the following code, I would get at least one of the above
messages when run on the Linux CI container:

```bash
for i in $(seq 1 32); do
  dig @localhost asdf +short &
done
```

The error hasn't recurred after this change, in spite of running the
above code a dozen times.
2021-01-19 07:27:53 -08:00
Brian Cunnie
1b6d72cf49 🐞 dig: "any" type query works on macOS & Linux
The behavior of `dig` version **9.11.25-RedHat-9.11.25-2.fc32** differs
from macOS's `dig` version **9.10.6**. In other words, this test passes
on my mac but not until now on (Linux-based) CI.

I also took the opportunity to refactor our `dig` arguments to conform with
the suggested usage:

> Usage:  dig [@global-server] [domain] [q-type] [q-class] {q-opt}

fixes <https://ci.nono.io/teams/main/pipelines/sslip.io/jobs/unit/builds/145>:
```
  Expected
      <int>: 9
  to match exit code:
      <int>: 0
```

Note that for the `any` test I had to append an additional `+notcp`
argument to avoid an attempted TCP connection. I suspect a bug in `dig`:
```
dig any sslip.io @localhost
;; Connection to 127.0.0.1#53(127.0.0.1) for sslip.io failed: connection refused.
```
2021-01-19 07:05:17 -08:00
Brian Cunnie
b534bcd0cb Formatting only: goimports -w 2021-01-19 07:04:07 -08:00
Brian Cunnie
bdb0b08de8 🐞 wildcard-dns-http-server: multiple TXT records
- it appears that Let's Encrypt requires setting at least two TXT
records; before I only allowed one to be set; now you can set as many as
you want.

- our records had a TTL of 0 seconds; I bumped it to 60: long enough to
get a cert, short enough to refesh for a second attempt if the first one
failed.
2021-01-18 16:52:27 -08:00
Brian Cunnie
6d0d3b9be5 🐞 HTTP server returns body confirming change
Previously we weren't returning a response when `acme.sh` updated our
TXT record, but the acme-dns endpoint specifies a
[response](https://github.com/joohoi/acme-dns#response), and acme.sh
expects [a
response](b7a3fe05a4/dnsapi/dns_acmedns.sh (L38)).

fixes:
```
[Mon Jan 18 19:09:26 UTC 2021] invalid response of acme-dns
[Mon Jan 18 19:09:26 UTC 2021] Error add txt for domain:_acme-challenge.34-83-219-164.sslip.io
```
2021-01-18 14:19:06 -08:00
Brian Cunnie
a346b7d668 Dockerfile: cunnie/sslip.io-dns-server → 2.0.0 2021-01-18 11:01:05 -08:00
Brian Cunnie
b2396ff081 🐞 bin/make_all compiles in correct directory
We had moved the DNS server to a sub-directory to make room for a
sibling application, a small DNS server + small HTTP server.

fixes:
```
cannot find package "main.go" in any of:
	/usr/local/Cellar/go/1.15.6/libexec/src/main.go (from $GOROOT)
	/Users/cunnie/go/src/main.go (from $GOPATH)
```
2021-01-18 10:42:54 -08:00
Brian Cunnie
eb032a78d8 BOSH release: 2.0.0: 🐞 _acme-challenge. delegation 2.0.0 2021-01-18 10:21:09 -08:00
Brian Cunnie
e33c33269f 🐞 Respond to Let's Encrypt Challenges properly
When querying for a record with `_acme-challenge.` and an embedded IP
address, we mistakenly responded with an answer with the
**authoritative** flag set and the **SOA** record in the **Authorities**
section. But that was wrong: we should NOT have set the
**authoritative** flag, and we should have included the **NS** record,
not the **SOA** record, in the **Authorities** section.

Created much-needed integration-level tests. The existing unit tests
were difficult to set up, were too constricting when refactoring, and
were less meaningful than the integration tests.

Hygiene:

- Eliminated the `ErrNotFound` error; it was hack: it was a substitute
for returning an empty set, which I wasn't handling correctly. Now, when
a record isn't found (usually because it's not a customized domain), it
returns an empty set, not an error.

- Used the `dnsmessage` capitalization convention where applicable, e.g.
`SOAResource()` not `SOAResource()`

- Replaced painful low-level copying with the `dnsmessage`'s utility
functions, `NewName()` and `MustNewName()`

This change triggered a huge rewrite, for we had hard-coded the
**authoritative** flag. The newer code is more flexible, and lays the
groundwork for future changes such as including IP addresses in the
**Additionals** section.
2021-01-18 07:32:13 -08:00
Brian Cunnie
7c099f5843 Docs: procuring a wildcard certificate (beta)
The docs are correct, but the code isn't yet ready.
2021-01-16 11:48:02 -08:00
Brian Cunnie
f42417da7e _acme-challenge. TXT records return NS not SOA
This change is to enable wildcard certificates via DNS challenge.

My earlier attempt failed: when queried for TXT for
`_acme-challenge.127-0-0-1.sslip.io`, I returned an authoritative
response with the Authorities section containing the SOA record, which
signaled, "There is no TXT record, of that I am sure." Even though I had
configured an NS record `_acme-challenge.127-0-0-1.sslip.io` to return
`127-0-0-1.sslip.io`.

Now I return an authoritative response with an NS record, not an SOA
record, in the response.

But that's still not enough, and I'd like to do the following changes:

- When queried for a DNS-01 challenge, e.g.
`_acme-challenge.127-0-0-1.sslip.io`, I return a _non-authoritative_
response with the NS record. This is the behavior of, say, `dig ns
sslip.io @a0.nic.io.`

- When queried for any NS records, I return an Additionals section
with the IP addresses.
2021-01-12 06:17:37 -08:00
Brian Cunnie
0d0acfe318 Docs: update sample procedure to procure wildcard
**This process still does not work**. We need to fix our sslip.io DNS
server code. That being said, once our DNS server code is fixed, this
process _should_ work.

As much as we'd have liked to use `joohoi/acme-dns`, it didn't work with
our setup, possibly due to our DNS server code brokenness, mentioned
above. At any rate, we have our own `acme-dns` replacement, which we
intend to use going forward.
2021-01-11 07:37:50 -08:00
Brian Cunnie
833058d458 dnsmessage.NewName() makes code shorter & readable
Previously I handcoded the `dnsmessage.Name{}` structs, but this
function makes it much more easy.

The only downside is that I consistently ignore any errors returned.

I scoped the change to the code, but not the tests.
2021-01-10 10:19:26 -08:00
Brian Cunnie
3f61b73290 Dockerfile for DNS/HTTP wildcard server
This DNS/HTTP server enables the procurement of wildcard certs for
sslip.io subdomains.

Drive-by:

- Removed the apostrophe from the initialized TXT string so that
cutting-and-pasting the string is less difficult (but the backslashes
and double quotes are still a pain).

- The DNS/HTTP server logs output when the TXT record is updated. We log
most actions, and this is perhaps the most important one, so it was an
oversight that we didn't log it.
2021-01-10 06:11:38 -08:00
Brian Cunnie
be1803de6d Custom DNS/HTTP server combo updates TXT record
This is an [acme-dns](https://github.com/joohoi/acme-dns)-compatible
webserver that allows you to update the TXT record to verify domain
ownership to the certificate authority in order to procure a wildcard
certificate.
2021-01-09 12:14:04 -08:00
Brian Cunnie
0614f2b059 Custom DNS Server returns only TXT records
This small DNS server only returns one type of record, a TXT record,
meant to be a token assigned by a certificate authority (e.g. Let's
Encrypt) to verify domain ownership.

The TXT record will be updateable by an API endpoint on the webserver
(same executable as the DNS server), but I haven't yet written that
portion.

Drive-by: in our _other_ (main) sslip.io DNS server, I changed `break` →
`continue` in the main loop. Had we gotten a malformed UDP packet, we
would have exited, but now we continue to the next packet. Exiting is
not that big a deal—`monit` would have restarted the server—but moving
on to the next packet is a more robust approach.

[#6]
2021-01-09 10:41:21 -08:00
Brian Cunnie
404e9b2365 Instructions for procuring a wildcard certificate
Warning: these instructions do not work & are incomplete.

I had high hopes for [acme-dns](https://github.com/joohoi/acme-dns), but
it seems much too baroque for my purposes—authentication, subdomains,
CNAMEs. It seems quite clever for a use case that is much more
complicated than mine.

I've resolved to write an _acme-dns_-compatible HTTP server & DNS server
to meet my much simpler needs.
2021-01-03 19:15:48 -08:00
Brian Cunnie
dfde2f2124 Move sslip.io-dns-server source code to a subdir
I'm going to create a simple HTTP/DNS server that has the same API as
[acme-dns](https://github.com/joohoi/acme-dns) but isn't so complicated,
and I want that code to be next to the regular DNS server code.

caveat: Although I've made changes to the packaging script, I have not
tested them, and I don't intend to, for I don't plan to ever create
another BOSH release, and that breaks my 💔.
2021-01-03 18:53:46 -08:00
Brian Cunnie
a4bb454118 Dockerfile: cunnie/sslip.io-dns-server → 1.3.1 2020-12-24 12:32:22 -08:00
Brian Cunnie
bea9cde6f0 BOSH release: 1.3.1: Special NS records for _acme-challenge.
`DEVELOPER.md` had the wrong tests (mostly missing newlines); that's
been fixed. Also, I added a new test for DNS records which contain
`_acme-challenge.`, which may enable users to generate wildcard certs
for their sslip.io domains.
1.3.1
2020-12-24 12:11:58 -08:00