diff --git a/.github/workflows/build-standalone.yml b/.github/workflows/build-standalone.yml index 8ff5ada..85f978e 100644 --- a/.github/workflows/build-standalone.yml +++ b/.github/workflows/build-standalone.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: GO_VERSION: - - 1.24.1 + - 1.24.4 steps: - name: Checkout diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 12eda63..a8e081e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: GO_VERSION: - - 1.24.1 + - 1.24.4 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7c4c2e..227cab6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: GO_VERSION: - - 1.24.1 + - 1.24.4 steps: - name: Checkout diff --git a/build/Dockerfile-boulder b/build/Dockerfile-boulder index 65e6935..1a67659 100644 --- a/build/Dockerfile-boulder +++ b/build/Dockerfile-boulder @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM letsencrypt/boulder-tools:go1.24.1_2025-04-30 AS boulder-tools +FROM letsencrypt/boulder-tools:go1.24.4_2025-06-06 AS boulder-tools FROM ubuntu:noble diff --git a/build/Dockerfile-control b/build/Dockerfile-control index 5860f95..82031b4 100644 --- a/build/Dockerfile-control +++ b/build/Dockerfile-control @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM letsencrypt/boulder-tools:go1.24.1_2025-04-30 AS boulder-tools +FROM letsencrypt/boulder-tools:go1.24.4_2025-06-06 AS boulder-tools FROM ubuntu:noble AS builder diff --git a/build/build.sh b/build/build.sh index a239d0d..130bac2 100755 --- a/build/build.sh +++ b/build/build.sh @@ -8,7 +8,7 @@ TMP_DIR=$(pwd)/tmp rm -rf $TMP_DIR && mkdir -p $TMP_DIR/{admin,bin,logs,src} boulderDir=$TMP_DIR/src -boulderTag="release-2025-05-27" +boulderTag="v0.20250707.0" boulderUrl="https://github.com/letsencrypt/boulder/" cloneDir=$(pwd)/.. diff --git a/build/docker-compose.yml b/build/docker-compose.yml index cf6585c..71ca7e0 100644 --- a/build/docker-compose.yml +++ b/build/docker-compose.yml @@ -12,9 +12,9 @@ services: GO_VERSION: 1.24.1 environment: # To solve HTTP-01 and TLS-ALPN-01 challenges, change the IP in FAKE_DNS - # to the IP address where your ACME client's solver is listening. - # FAKE_DNS: 172.17.0.1 - FAKE_DNS: 10.77.77.77 + # to the IP address where your ACME client's solver is listening. This is + # pointing at the boulder service's "public" IP, where challtestsrv is. + FAKE_DNS: 64.112.117.122 BOULDER_CONFIG_DIR: labca/config GOCACHE: /boulder/.gocache/go-build GOFLAGS: -mod=vendor @@ -26,12 +26,10 @@ services: networks: bouldernet: ipv4_address: 10.77.77.77 - integrationtestnet: - ipv4_address: 10.88.88.88 - redisnet: - ipv4_address: 10.33.33.33 - consulnet: - ipv4_address: 10.55.55.55 + publicnet: + ipv4_address: 64.112.117.122 + publicnet2: + ipv4_address: 64.112.117.134 # Use consul as a backup to Docker's embedded DNS server. If there's a name # Docker's DNS server doesn't know about, it will forward the query to this # IP (running consul). @@ -40,15 +38,17 @@ services: # are configured via the ServerAddress field of cmd.GRPCClientConfig. # TODO: Remove this when ServerAddress is deprecated in favor of SRV records # and DNSAuthority. - dns: 10.55.55.10 + dns: 10.77.77.10 extra_hosts: - # Allow the boulder container to be reached as "ca.example.org", so that - # we can put that name inside our integration test certs (e.g. as a crl + # Allow the boulder container to be reached as "ca.example.org", so we + # can put that name inside our integration test certs (e.g. as a crl # url) and have it look like a publicly-accessible name. - - "ca.example.org:10.77.77.77" + # TODO(#8215): Move s3-test-srv to a separate service. + - "ca.example.org:64.112.117.122" # Allow the boulder container to be reached as "integration.trust", for # similar reasons, but intended for use as a SAN rather than a CRLDP. - - "integration.trust:10.77.77.77" + # TODO(#8215): Move observer's probe target to a separate service. + - "integration.trust:64.112.117.122" ports: - 4001:4001 # ACMEv2 - 4002:4002 # OCSP @@ -69,7 +69,7 @@ services: restart: always bmysql: - image: mariadb:10.5 + image: mariadb:10.6.22 volumes: - dbdata:/var/lib/mysql networks: @@ -89,12 +89,13 @@ services: bredis: image: redis:6.2.7 volumes: + - ./test/:/test/:cached - boulder_data:/opt/boulder/labca - certificates:/opt/boulder/labca/certs command: redis-server /opt/boulder/labca/redis-ratelimits.config networks: - redisnet: - ipv4_address: 10.33.33.4 + bouldernet: + ipv4_address: 10.77.77.4 restart: always bconsul: @@ -105,8 +106,6 @@ services: - boulder_data:/opt/boulder/labca - certificates:/opt/boulder/labca/certs networks: - consulnet: - ipv4_address: 10.55.55.10 bouldernet: ipv4_address: 10.77.77.10 command: "consul agent -dev -config-format=hcl -config-file=/opt/boulder/labca/consul/config.hcl" @@ -182,8 +181,7 @@ services: bpkimetal: image: ghcr.io/pkimetal/pkimetal:v1.20.0 networks: - bouldernet: - ipv4_address: 10.77.77.9 + - bouldernet restart: always volumes: @@ -199,17 +197,34 @@ volumes: certificates: networks: - # This network is primarily used for boulder services. It is also used by - # challtestsrv, which is used in the integration tests. + # This network represents the data-center internal network. It is used for + # boulder services and their infrastructure, such as consul, mariadb, and + # redis. bouldernet: driver: bridge ipam: driver: default config: - subnet: 10.77.77.0/24 + # Only issue DHCP addresses in the top half of the range, to avoid + # conflict with static addresses. + ip_range: 10.77.77.128/25 + + # This network represents the public internet. It uses a real public IP space + # (that Let's Encrypt controls) so that our integration tests are happy to + # validate and issue for it. It is used by challtestsrv, which binds to + # 64.112.117.122:80 and :443 for its HTTP-01 challenge responder. + # + # TODO(#8215): Put akamai-test-srv and s3-test-srv on this network. + publicnet: + driver: bridge + ipam: + driver: default + config: + - subnet: 64.112.117.0/25 # This network is used for two things in the integration tests: - # - challtestsrv binds to 10.88.88.88:443 for its tls-alpn-01 challenge + # - challtestsrv binds to 64.112.117.134:443 for its tls-alpn-01 challenge # responder, to avoid interfering with the HTTPS port used for testing # HTTP->HTTPS redirects during http-01 challenges. Note: this could # probably be updated in the future so that challtestsrv can handle @@ -217,24 +232,13 @@ networks: # - test/v2_integration.py has some test cases that start their own HTTP # server instead of relying on challtestsrv, because they want very # specific behavior. For these cases, v2_integration.py creates a Python - # HTTP server and binds it to 10.88.88.88:80. - integrationtestnet: + # HTTP server and binds it to 64.112.117.134:80. + # + # TODO(#8215): Deprecate this network, replacing it with individual IPs within + # the existing publicnet. + publicnet2: driver: bridge ipam: driver: default config: - - subnet: 10.88.88.0/24 - - redisnet: - driver: bridge - ipam: - driver: default - config: - - subnet: 10.33.33.0/24 - - consulnet: - driver: bridge - ipam: - driver: default - config: - - subnet: 10.55.55.0/24 + - subnet: 64.112.117.128/25 diff --git a/build/tmp.patch b/build/tmp.patch index 929dea4..214ae34 100644 --- a/build/tmp.patch +++ b/build/tmp.patch @@ -1,5 +1,5 @@ diff --git a/docker-compose.yml b/docker-compose.yml -index e981e30ec..cf6585c65 100644 +index b9a8ac069..71ca7e0be 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: @@ -27,17 +27,17 @@ index e981e30ec..cf6585c65 100644 networks: bouldernet: ipv4_address: 10.77.77.77 -@@ -90,7 +89,8 @@ services: - bredis: +@@ -91,7 +90,8 @@ services: image: redis:6.2.7 volumes: + - ./test/:/test/:cached - - /home/labca/boulder_labca:/opt/boulder/labca + - boulder_data:/opt/boulder/labca + - certificates:/opt/boulder/labca/certs command: redis-server /opt/boulder/labca/redis-ratelimits.config networks: - redisnet: -@@ -102,35 +102,37 @@ services: + bouldernet: +@@ -103,33 +103,35 @@ services: depends_on: - control volumes: @@ -45,8 +45,6 @@ index e981e30ec..cf6585c65 100644 + - boulder_data:/opt/boulder/labca + - certificates:/opt/boulder/labca/certs networks: - consulnet: - ipv4_address: 10.55.55.10 bouldernet: ipv4_address: 10.77.77.10 command: "consul agent -dev -config-format=hcl -config-file=/opt/boulder/labca/consul/config.hcl" @@ -86,7 +84,7 @@ index e981e30ec..cf6585c65 100644 logging: driver: "json-file" options: -@@ -147,30 +149,28 @@ services: +@@ -146,30 +148,28 @@ services: - 80:80 - 443:443 volumes: @@ -131,7 +129,7 @@ index e981e30ec..cf6585c65 100644 expose: - 3030 environment: -@@ -188,6 +188,15 @@ services: +@@ -186,6 +186,15 @@ services: volumes: dbdata: @@ -146,4 +144,4 @@ index e981e30ec..cf6585c65 100644 + certificates: networks: - # This network is primarily used for boulder services. It is also used by + # This network represents the data-center internal network. It is used for diff --git a/commander b/commander index e592ec4..ae475aa 100755 --- a/commander +++ b/commander @@ -167,8 +167,6 @@ case $txt in ;; "test-email") read recipient - cd /opt/boulder - docker compose exec boulder bin/boulder mail-tester --config labca/config/expiration-mailer.json $recipient 2>&1 ;; "boulder-start") cd /opt/boulder diff --git a/dev/versions b/dev/versions index 7f531b7..8f89cbd 100755 --- a/dev/versions +++ b/dev/versions @@ -114,7 +114,7 @@ grep GO_VERSION ../boulder/docker-compose.yml | sed -e "s/\s*GO_VERSION:/ /" colorGoVersion2 build/docker-compose.yml $goversion echo -db_migrs=$(ls -1 ../boulder/sa/db/boulder_sa/ | grep -v 20240304000000_CertificateProfiles.sql | grep -v 20250115000000_AuthzProfiles.sql | wc -l) +db_migrs=$(ls -1 ../boulder/sa/db/boulder_sa/ | grep -v 20240304000000_CertificateProfiles.sql | grep -v 20250115000000_AuthzProfiles.sql | grep -v 20250519000000_NullRegistrationsContact.sql | wc -l) db_patches=$(ls -1 ../labca/patches/db_migrations* | wc -l) echo -n "Database migrations " colorEqual $db_migrs $db_patches diff --git a/gui/apply-boulder b/gui/apply-boulder index bd384e2..01b7bf0 100755 --- a/gui/apply-boulder +++ b/gui/apply-boulder @@ -67,7 +67,6 @@ perl -i -p0e "s/(\"dnsStaticResolvers\": \[\n).*?(\s+\],)/\1\t\t\t\"$PKI_DNS\"\2 perl -i -p0e "s/(\"dnsStaticResolvers\": \[\n).*?(\s+\],)/\1\t\t\t\"$PKI_DNS\"\2/igs" config/remoteva-c.json perl -i -p0e "s/(\"dnsStaticResolvers\": \[\n).*?(\s+\],)/\1\t\t\t\"$PKI_DNS\"\2/igs" config/va.json perl -i -p0e "s/(\"dnsStaticResolvers\": \[\n).*?(\s+\],)/\1\t\t\t\"$PKI_DNS\"\2/igs" config/bad-key-revoker.json -perl -i -p0e "s/(\"dnsStaticResolvers\": \[\n).*?(\s+\],)/\1\t\t\t\"$PKI_DNS\"\2/igs" config/expiration-mailer.json # Disable DOH as long as it is a feature... sed -i -e "s/\(\"DOH\":\s*\).*/\1false/" config/remoteva-a.json @@ -197,7 +196,6 @@ if [ "$PKI_EXTENDED_TIMEOUT" == "1" ]; then sed -i -e "s/\"timeout\": \"15s\"/\"timeout\": \"30s\"/" config/admin.json sed -i -e "s/\"timeout\": \"15s\"/\"timeout\": \"30s\"/" config/wfe2.json sed -i -e "s/\"timeout\": \"20s\"/\"timeout\": \"40s\"/" config/wfe2.json - sed -i -e "s/\"timeout\": \"15s\"/\"timeout\": \"30s\"/" config/expiration-mailer.json sed -i -e "s/\"timeout\": \"15s\"/\"timeout\": \"30s\"/" config/ra.json sed -i -e "s/\"timeout\": \"20s\"/\"timeout\": \"40s\"/" config/ra.json sed -i -e "s/\"timeout\": \"15s\"/\"timeout\": \"30s\"/" config/crl-storer.json @@ -214,16 +212,6 @@ sed -i -e "s/\"port\": \".*\"/\"port\": \"$PKI_EMAIL_PORT\"/" config/bad-key-rev sed -i -e "s/\"username\": \".*\"/\"username\": \"$PKI_EMAIL_USER\"/" config/bad-key-revoker.json sed -i -e "s/\"from\": \".*\"/\"from\": \"$PKI_EMAIL_FROM\"/" config/bad-key-revoker.json sed -i -e "s|\"SMTPTrustedRootFile\": \".*\"|\"SMTPTrustedRootFile\": \"$PKI_EMAIL_TRUST\"|" config/bad-key-revoker.json -sed -i -e "s/\"server\": \".*\"/\"server\": \"$PKI_EMAIL_SERVER\"/" config/expiration-mailer.json -sed -i -e "s/\"port\": \".*\"/\"port\": \"$PKI_EMAIL_PORT\"/" config/expiration-mailer.json -sed -i -e "s/\"username\": \".*\"/\"username\": \"$PKI_EMAIL_USER\"/" config/expiration-mailer.json -sed -i -e "s/\"from\": \".*\"/\"from\": \"$PKI_EMAIL_FROM\"/" config/expiration-mailer.json -sed -i -e "s|\"SMTPTrustedRootFile\": \".*\"|\"SMTPTrustedRootFile\": \"$PKI_EMAIL_TRUST\"|" config/expiration-mailer.json -sed -i -e "s/\"server\": \".*\"/\"server\": \"$PKI_EMAIL_SERVER\"/" config/notify-mailer.json -sed -i -e "s/\"port\": \".*\"/\"port\": \"$PKI_EMAIL_PORT\"/" config/notify-mailer.json -sed -i -e "s/\"username\": \".*\"/\"username\": \"$PKI_EMAIL_USER\"/" config/notify-mailer.json -sed -i -e "s/\"from\": \".*\"/\"from\": \"$PKI_EMAIL_FROM\"/" config/notify-mailer.json -sed -i -e "s|\"SMTPTrustedRootFile\": \".*\"|\"SMTPTrustedRootFile\": \"$PKI_EMAIL_TRUST\"|" config/notify-mailer.json sed -i -e "s/\"purgeInterval\": \".*\"/\"purgeInterval\": \"1s\"/" config/akamai-purger.json diff --git a/install b/install index 2d4c175..ced8a1d 100755 --- a/install +++ b/install @@ -30,7 +30,7 @@ dockerComposeVersion="v2.5.0" labcaUrl="https://github.com/hakwerk/labca/" boulderUrl="https://github.com/letsencrypt/boulder/" -boulderTag="release-2025-05-27" +boulderTag="v0.20250707.0" # # Color configuration @@ -620,10 +620,6 @@ config_boulder() { cp core/interfaces.go "$boulderLabCADir/.backup/" cp policy/pa.go "$boulderLabCADir/.backup/" cp ra/ra.go "$boulderLabCADir/.backup/" - cp mail/mailer.go "$boulderLabCADir/.backup/" - cp cmd/expiration-mailer/main.go "$boulderLabCADir/.backup/" - cp cmd/notify-mailer/main.go "$boulderLabCADir/.backup/" - cp cmd/contact-auditor/main.go "$boulderLabCADir/.backup/" cp cmd/bad-key-revoker/main.go "$boulderLabCADir/.backup/" cp cmd/cert-checker/main.go "$boulderLabCADir/.backup/" cp cmd/log-validator/main.go "$boulderLabCADir/.backup/" diff --git a/mail-tester.go b/mail-tester.go deleted file mode 100644 index c1779a3..0000000 --- a/mail-tester.go +++ /dev/null @@ -1,169 +0,0 @@ -package notmain - -import ( - "context" - "crypto/x509" - "flag" - "fmt" - netmail "net/mail" - "os" - "time" - - "github.com/letsencrypt/boulder/bdns" - "github.com/letsencrypt/boulder/cmd" - bconfig "github.com/letsencrypt/boulder/config" - "github.com/letsencrypt/boulder/features" - bmail "github.com/letsencrypt/boulder/mail" -) - -const usageString = ` -usage: -mail-tester --config - -args: - config File path to the configuration file for this service - recipient Email address to send an email to -` - -type config struct { - Mailer struct { - DebugAddr string - DB cmd.DBConfig - cmd.SMTPConfig - - From string - Subject string - - CertLimit int - NagTimes []string - // How much earlier (than configured nag intervals) to - // send reminders, to account for the expected delay - // before the next expiration-mailer invocation. - NagCheckInterval string - // Path to a text/template email template - EmailTemplate string - - Frequency bconfig.Duration - - TLS cmd.TLSConfig - SAService *cmd.GRPCClientConfig - - DNSTries int - DNSStaticResolvers []string - DNSTimeout string - DNSAllowLoopbackAddresses bool - - // Path to a file containing a list of trusted root certificates for use - // during the SMTP connection (as opposed to the gRPC connections). - SMTPTrustedRootFile string - - UserAgent string - - Features features.Config - } - - Syslog cmd.SyslogConfig - OpenTelemetry cmd.OpenTelemetryConfig -} - -func main() { - usage := func() { - fmt.Fprintf(os.Stderr, usageString) - os.Exit(1) - } - - configFile := flag.String("config", "", "File path to the configuration file for this service") - flag.Parse() - if len(os.Args) <= 3 || *configFile == "" { - usage() - } - - args := flag.Args() - recipient := args[0] - - var c config - err := cmd.ReadConfigFile(*configFile, &c) - cmd.FailOnError(err, "Reading JSON config file into config structure") - - features.Set(c.Mailer.Features) - - scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.Mailer.DebugAddr) - defer oTelShutdown(context.Background()) - logger.Info(cmd.VersionString()) - - tlsConfig, err := c.Mailer.TLS.Load(scope) - cmd.FailOnError(err, "TLS config") - - clk := cmd.Clock() - - dnsTimeout, err := time.ParseDuration(c.Mailer.DNSTimeout) - cmd.FailOnError(err, "Couldn't parse DNS timeout") - dnsTries := c.Mailer.DNSTries - if dnsTries < 1 { - dnsTries = 1 - } - var resolver bdns.Client - servers, err := bdns.NewStaticProvider(c.Mailer.DNSStaticResolvers) - cmd.FailOnError(err, "Couldn't start static DNS server resolver") - if !c.Mailer.DNSAllowLoopbackAddresses { - r := bdns.New( - dnsTimeout, - servers, - scope, - clk, - dnsTries, - c.Mailer.UserAgent, - logger, - tlsConfig) - resolver = r - } else { - r := bdns.NewTest(dnsTimeout, servers, scope, clk, dnsTries, c.Mailer.UserAgent, logger, tlsConfig) - resolver = r - } - - var smtpRoots *x509.CertPool - smtpSkipVerify := false - if c.Mailer.SMTPTrustedRootFile == "InsecureSkipVerify" { - smtpSkipVerify = true - } else if c.Mailer.SMTPTrustedRootFile != "" { - pem, err := os.ReadFile(c.Mailer.SMTPTrustedRootFile) - cmd.FailOnError(err, "Loading trusted roots file") - smtpRoots = x509.NewCertPool() - if !smtpRoots.AppendCertsFromPEM(pem) { - cmd.FailOnError(nil, "Failed to parse root certs PEM") - } - } - - fromAddress, err := netmail.ParseAddress(c.Mailer.From) - cmd.FailOnError(err, fmt.Sprintf("Could not parse from address: %s", c.Mailer.From)) - - smtpPassword, err := c.Mailer.PasswordConfig.Pass() - cmd.FailOnError(err, "Failed to load SMTP password") - mailClient := bmail.New( - c.Mailer.Server, - c.Mailer.Port, - c.Mailer.Username, - smtpPassword, - smtpRoots, - smtpSkipVerify, - resolver, - *fromAddress, - logger, - scope, - 1*time.Second, - 5*60*time.Second) - - conn, err := mailClient.Connect() - cmd.FailOnError(err, "mail-tester failed to connect") - defer conn.Close() - - recipients := []string{} - recipients = append(recipients, recipient) - - err = conn.SendMail(recipients, "Test Email from LabCA", "Test sending email from the LabCA server") - cmd.FailOnError(err, "mail-tester has failed") -} - -func init() { - cmd.RegisterCommand("mail-tester", main, &cmd.ConfigValidator{Config: &config{}}) -} diff --git a/patch-cfg.sh b/patch-cfg.sh index b1799a0..548e721 100755 --- a/patch-cfg.sh +++ b/patch-cfg.sh @@ -14,8 +14,6 @@ boulderLabCADir="${2:-labca}" $SUDO patch -p1 -o "$boulderLabCADir/entrypoint.sh" < $cloneDir/patches/entrypoint.patch cp test/startservers.py "$boulderLabCADir/startservers.py" -$SUDO patch -p1 -o "$boulderLabCADir/config/expiration-mailer.json" < $cloneDir/patches/config_expiration-mailer.patch -$SUDO patch -p1 -o "$boulderLabCADir/config/notify-mailer.json" < $cloneDir/patches/config_notify-mailer.patch $SUDO patch -p1 -o "$boulderLabCADir/config/bad-key-revoker.json" < $cloneDir/patches/config_bad-key-revoker.patch $SUDO patch -p1 -o "$boulderLabCADir/config/ocsp-responder.json" < $cloneDir/patches/config_ocsp-responder.patch $SUDO patch -p1 -o "$boulderLabCADir/config/publisher.json" < $cloneDir/patches/config_publisher.patch @@ -29,10 +27,10 @@ $SUDO patch -p1 -o "$boulderLabCADir/certs/generate.sh" < $cloneDir/patches/test chmod +x $boulderLabCADir/certs/generate.sh cp test/config/va*.json "$boulderLabCADir/config/" -perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],/igs" $boulderLabCADir/config/va.json -perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],/igs" $boulderLabCADir/config/remoteva-a.json -perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],/igs" $boulderLabCADir/config/remoteva-b.json -perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],/igs" $boulderLabCADir/config/remoteva-c.json +perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],\n\t\t\"dnsAllowLoopbackAddresses\": true,/igs" $boulderLabCADir/config/va.json +perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],\n\t\t\"dnsAllowLoopbackAddresses\": true,/igs" $boulderLabCADir/config/remoteva-a.json +perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],\n\t\t\"dnsAllowLoopbackAddresses\": true,/igs" $boulderLabCADir/config/remoteva-b.json +perl -i -p0e "s/\"dnsProvider\": \{.*?\t\t},/\"dnsStaticResolvers\": [\n\t\t\t\"127.0.0.1:8053\",\n\t\t\t\"127.0.0.1:8054\"\n\t\t],\n\t\t\"dnsAllowLoopbackAddresses\": true,/igs" $boulderLabCADir/config/remoteva-c.json perl -i -p0e "s/(\"accountURIPrefixes\": \[\n.*?\s+\])/\1,\n\t\t\"labcaDomains\": [\n\t\t]/igs" $boulderLabCADir/config/remoteva-a.json perl -i -p0e "s/(\"accountURIPrefixes\": \[\n.*?\s+\])/\1,\n\t\t\"labcaDomains\": [\n\t\t]/igs" $boulderLabCADir/config/remoteva-b.json perl -i -p0e "s/(\"accountURIPrefixes\": \[\n.*?\s+\])/\1,\n\t\t\"labcaDomains\": [\n\t\t]/igs" $boulderLabCADir/config/remoteva-c.json diff --git a/patch.sh b/patch.sh index 94ff6f7..5c8967a 100755 --- a/patch.sh +++ b/patch.sh @@ -15,6 +15,7 @@ if [ "$SUDO" == "" ]; then fi $SUDO patch -p1 < $cloneDir/patches/bad-key-revoker_main.patch +$SUDO patch -p1 < $cloneDir/patches/bdns_dns.patch $SUDO patch -p1 < $cloneDir/patches/boulder-ra_main.patch $SUDO patch -p1 < $cloneDir/patches/boulder-va_main.patch $SUDO patch -p1 < $cloneDir/patches/ca_ca.patch @@ -29,7 +30,6 @@ $SUDO patch -p1 < $cloneDir/patches/cert-checker_main.patch $SUDO patch -p1 < $cloneDir/patches/cmd_config.patch $SUDO patch -p1 < $cloneDir/patches/config_duration.patch $SUDO patch -p1 < $cloneDir/patches/config_rocsp_config.patch -$SUDO patch -p1 < $cloneDir/patches/contact-auditor_main.patch $SUDO patch -p1 < $cloneDir/patches/core_interfaces.patch $SUDO patch -p1 < $cloneDir/patches/crl-storer_main.patch $SUDO patch -p1 < $cloneDir/patches/db_migrations.patch @@ -37,22 +37,20 @@ $SUDO patch -p1 < $cloneDir/patches/db_migrations2.patch $SUDO patch -p1 < $cloneDir/patches/db_migrations3.patch $SUDO patch -p1 < $cloneDir/patches/db_migrations4.patch $SUDO patch -p1 < $cloneDir/patches/db_migrations5.patch -$SUDO patch -p1 < $cloneDir/patches/expiration-mailer_main.patch $SUDO patch -p1 < $cloneDir/patches/issuance_crl.patch $SUDO patch -p1 < $cloneDir/patches/issuance_issuer.patch $SUDO patch -p1 < $cloneDir/patches/linter_linter.patch $SUDO patch -p1 < $cloneDir/patches/log_prod_prefix.patch $SUDO patch -p1 < $cloneDir/patches/log_test_prefix.patch $SUDO patch -p1 < $cloneDir/patches/log_validator_validator.patch -$SUDO patch -p1 < $cloneDir/patches/mail_mailer.patch $SUDO patch -p1 < $cloneDir/patches/makefile.patch -$SUDO patch -p1 < $cloneDir/patches/notify-mailer_main.patch $SUDO patch -p1 < $cloneDir/patches/ocsp-responder_main.patch $SUDO patch -p1 < $cloneDir/patches/policy_pa.patch $SUDO patch -p1 < $cloneDir/patches/ra_ra.patch $SUDO patch -p1 < $cloneDir/patches/ratelimits_names.patch $SUDO patch -p1 < $cloneDir/patches/redis_config.patch $SUDO patch -p1 < $cloneDir/patches/remoteva_main.patch +$SUDO patch -p1 < $cloneDir/patches/reversed-hostname-checker_main.patch $SUDO patch -p1 < $cloneDir/patches/start.patch $SUDO patch -p1 < $cloneDir/patches/test_startservers.patch if [ "$SUDO" == "" ]; then @@ -76,10 +74,6 @@ sed -i -e "s/proxysql:6033/mysql:3306/" sa/db/dbconfig.yml sed -i -e "s/\(.*overrides.*\)/-- \1/" sa/db-users/boulder_sa.sql -mkdir -p "cmd/mail-tester" -cp $cloneDir/mail-tester.go cmd/mail-tester/main.go -perl -i -p0e "s/(\n\t\"github.com\/letsencrypt\/boulder\/cmd\")/\t_ \"github.com\/letsencrypt\/boulder\/cmd\/mail-tester\"\n\1/igs" cmd/boulder/main.go - perl -i -p0e "s/If you continue to encounter.*for troubleshooting and advice.//igs" sfe/pages/index.html perl -i -p0e "s/Note:<\/b> If you encounter.*troubleshooting and advice.//igs" sfe/pages/unpause-form.html perl -i -p0e "s/If you continue to encounter.*for troubleshooting and advice.//igs" sfe/pages/unpause-invalid-request.html diff --git a/patches/bad-key-revoker_main.patch b/patches/bad-key-revoker_main.patch index 212e0ef..f70a199 100644 --- a/patches/bad-key-revoker_main.patch +++ b/patches/bad-key-revoker_main.patch @@ -1,16 +1,8 @@ diff --git a/cmd/bad-key-revoker/main.go b/cmd/bad-key-revoker/main.go -index c333b88c3..8e9cc21bd 100644 +index 8e6cfac85..8880ed301 100644 --- a/cmd/bad-key-revoker/main.go +++ b/cmd/bad-key-revoker/main.go -@@ -18,6 +18,7 @@ import ( - "google.golang.org/grpc" - "google.golang.org/protobuf/types/known/emptypb" - -+ "github.com/letsencrypt/boulder/bdns" - "github.com/letsencrypt/boulder/cmd" - "github.com/letsencrypt/boulder/config" - "github.com/letsencrypt/boulder/core" -@@ -398,6 +399,11 @@ type Config struct { +@@ -270,6 +270,11 @@ type Config struct { TLS cmd.TLSConfig RAService *cmd.GRPCClientConfig @@ -22,59 +14,12 @@ index c333b88c3..8e9cc21bd 100644 // MaximumRevocations specifies the maximum number of certificates associated with // a key hash that bad-key-revoker will attempt to revoke. If the number of certificates // is higher than MaximumRevocations bad-key-revoker will error out and refuse to -@@ -417,6 +423,8 @@ type Config struct { +@@ -289,6 +294,8 @@ type Config struct { // or no work to do. BackoffIntervalMax config.Duration `validate:"-"` + UserAgent string + + // Deprecated: the bad-key-revoker no longer sends emails; we use ARI. + // TODO(#8199): Remove this config stanza entirely. Mailer struct { - cmd.SMTPConfig - // Path to a file containing a list of trusted root certificates for use -@@ -469,8 +477,36 @@ func main() { - cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to RA") - rac := rapb.NewRegistrationAuthorityClient(conn) - -+ dnsTimeout, err := time.ParseDuration(config.BadKeyRevoker.DNSTimeout) -+ cmd.FailOnError(err, "Couldn't parse DNS timeout") -+ dnsTries := config.BadKeyRevoker.DNSTries -+ if dnsTries < 1 { -+ dnsTries = 1 -+ } -+ var resolver bdns.Client -+ servers, err := bdns.NewStaticProvider(config.BadKeyRevoker.DNSStaticResolvers) -+ cmd.FailOnError(err, "Couldn't start static DNS server resolver") -+ if !config.BadKeyRevoker.DNSAllowLoopbackAddresses { -+ r := bdns.New( -+ dnsTimeout, -+ servers, -+ scope, -+ clk, -+ dnsTries, -+ config.BadKeyRevoker.UserAgent, -+ logger, -+ tlsConfig) -+ resolver = r -+ } else { -+ r := bdns.NewTest(dnsTimeout, servers, scope, clk, dnsTries, config.BadKeyRevoker.UserAgent, logger, tlsConfig) -+ resolver = r -+ } -+ - var smtpRoots *x509.CertPool -- if config.BadKeyRevoker.Mailer.SMTPTrustedRootFile != "" { -+ smtpSkipVerify := false -+ if config.BadKeyRevoker.Mailer.SMTPTrustedRootFile == "InsecureSkipVerify" { -+ smtpSkipVerify = true -+ } else if config.BadKeyRevoker.Mailer.SMTPTrustedRootFile != "" { - pem, err := os.ReadFile(config.BadKeyRevoker.Mailer.SMTPTrustedRootFile) - cmd.FailOnError(err, "Loading trusted roots file") - smtpRoots = x509.NewCertPool() -@@ -490,6 +526,8 @@ func main() { - config.BadKeyRevoker.Mailer.Username, - smtpPassword, - smtpRoots, -+ smtpSkipVerify, -+ resolver, - *fromAddress, - logger, - scope, diff --git a/patches/bdns_dns.patch b/patches/bdns_dns.patch new file mode 100644 index 0000000..f0ff169 --- /dev/null +++ b/patches/bdns_dns.patch @@ -0,0 +1,81 @@ +diff --git a/bdns/dns.go b/bdns/dns.go +index 5d297f3ef..9eabf1239 100644 +--- a/bdns/dns.go ++++ b/bdns/dns.go +@@ -21,6 +21,7 @@ import ( + "github.com/miekg/dns" + "github.com/prometheus/client_golang/prometheus" + ++ "github.com/letsencrypt/boulder/features" + "github.com/letsencrypt/boulder/iana" + blog "github.com/letsencrypt/boulder/log" + "github.com/letsencrypt/boulder/metrics" +@@ -77,22 +78,30 @@ func New( + ) Client { + var client exchanger + +- // Clone the default transport because it comes with various settings +- // that we like, which are different from the zero value of an +- // `http.Transport`. +- transport := http.DefaultTransport.(*http.Transport).Clone() +- transport.TLSClientConfig = tlsConfig +- // The default transport already sets this field, but it isn't +- // documented that it will always be set. Set it again to be sure, +- // because Unbound will reject non-HTTP/2 DoH requests. +- transport.ForceAttemptHTTP2 = true +- client = &dohExchanger{ +- clk: clk, +- hc: http.Client{ +- Timeout: readTimeout, +- Transport: transport, +- }, +- userAgent: userAgent, ++ if features.Get().DOH { ++ // Clone the default transport because it comes with various settings ++ // that we like, which are different from the zero value of an ++ // `http.Transport`. ++ transport := http.DefaultTransport.(*http.Transport).Clone() ++ transport.TLSClientConfig = tlsConfig ++ // The default transport already sets this field, but it isn't ++ // documented that it will always be set. Set it again to be sure, ++ // because Unbound will reject non-HTTP/2 DoH requests. ++ transport.ForceAttemptHTTP2 = true ++ client = &dohExchanger{ ++ clk: clk, ++ hc: http.Client{ ++ Timeout: readTimeout, ++ Transport: transport, ++ }, ++ userAgent: userAgent, ++ } ++ } else { ++ client = &dns.Client{ ++ // Set timeout for underlying net.Conn ++ ReadTimeout: readTimeout, ++ Net: "udp", ++ } + } + + queryTime := prometheus.NewHistogramVec( +@@ -273,10 +282,17 @@ func (dnsClient *impl) exchangeOne(ctx context.Context, hostname string, qtype u + case r := <-ch: + if r.err != nil { + var isRetryable bool +- // According to the http package documentation, retryable +- // errors emitted by the http package are of type *url.Error. +- var urlErr *url.Error +- isRetryable = errors.As(r.err, &urlErr) && urlErr.Temporary() ++ if features.Get().DOH { ++ // According to the http package documentation, retryable ++ // errors emitted by the http package are of type *url.Error. ++ var urlErr *url.Error ++ isRetryable = errors.As(r.err, &urlErr) && urlErr.Temporary() ++ } else { ++ // According to the net package documentation, retryable ++ // errors emitted by the net package are of type *net.OpError. ++ var opErr *net.OpError ++ isRetryable = errors.As(r.err, &opErr) && opErr.Temporary() ++ } + hasRetriesLeft := tries < dnsClient.maxTries + if isRetryable && hasRetriesLeft { + tries++ diff --git a/patches/boulder-va_main.patch b/patches/boulder-va_main.patch index 691d7dc..d3b16ca 100644 --- a/patches/boulder-va_main.patch +++ b/patches/boulder-va_main.patch @@ -1,8 +1,8 @@ diff --git a/cmd/boulder-va/main.go b/cmd/boulder-va/main.go -index 981c4f9b5..9d5db072d 100644 +index 5086a3923..f557f33b0 100644 --- a/cmd/boulder-va/main.go +++ b/cmd/boulder-va/main.go -@@ -52,6 +52,7 @@ type Config struct { +@@ -53,6 +53,7 @@ type Config struct { // Deprecated and ignored MaxRemoteValidationFailures int `validate:"omitempty,min=0,required_with=RemoteVAs"` Features features.Config @@ -10,12 +10,30 @@ index 981c4f9b5..9d5db072d 100644 } Syslog cmd.SyslogConfig -@@ -152,7 +153,8 @@ func main() { +@@ -82,12 +83,16 @@ func main() { + clk := cmd.Clock() + + var servers bdns.ServerProvider ++ proto := "udp" ++ if features.Get().DOH { ++ proto = "tcp" ++ } + + if len(c.VA.DNSStaticResolvers) != 0 { + servers, err = bdns.NewStaticProvider(c.VA.DNSStaticResolvers) + cmd.FailOnError(err, "Couldn't start static DNS server resolver") + } else { +- servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, "tcp") ++ servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, proto) + cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver") + } + defer servers.Stop() +@@ -149,7 +154,8 @@ func main() { c.VA.AccountURIPrefixes, va.PrimaryPerspective, "", -- bdns.IsReservedIP) -+ bdns.IsReservedIP, +- iana.IsReservedAddr) ++ iana.IsReservedAddr, + c.VA.LabCADomains) cmd.FailOnError(err, "Unable to create VA server") diff --git a/patches/cmd_config.patch b/patches/cmd_config.patch index bccf4a6..f6b0049 100644 --- a/patches/cmd_config.patch +++ b/patches/cmd_config.patch @@ -1,8 +1,8 @@ diff --git a/cmd/config.go b/cmd/config.go -index f8b6b847f..38ea91f33 100644 +index 13842fdf9..33cb282cb 100644 --- a/cmd/config.go +++ b/cmd/config.go -@@ -469,7 +469,7 @@ type GRPCServerConfig struct { +@@ -471,7 +471,7 @@ type GRPCServerConfig struct { // this controls how long it takes before a client learns about changes to its // backends. // https://pkg.go.dev/google.golang.org/grpc/keepalive#ServerParameters diff --git a/patches/config_bad-key-revoker.patch b/patches/config_bad-key-revoker.patch index 11b12ad..bff7676 100644 --- a/patches/config_bad-key-revoker.patch +++ b/patches/config_bad-key-revoker.patch @@ -1,5 +1,5 @@ diff --git a/test/config/bad-key-revoker.json b/test/config/bad-key-revoker.json -index f4696dc2..b9c19ce3 100644 +index d70aadc5f..99dfde454 100644 --- a/test/config/bad-key-revoker.json +++ b/test/config/bad-key-revoker.json @@ -5,6 +5,13 @@ @@ -11,8 +11,8 @@ index f4696dc2..b9c19ce3 100644 + "127.0.0.1:8053", + "127.0.0.1:8054" + ], -+ "dnsTimeout": "3s", + "dnsAllowLoopbackAddresses": true, ++ "dnsTimeout": "3s", "tls": { "caCertFile": "test/certs/ipki/minica.pem", "certFile": "test/certs/ipki/bad-key-revoker.boulder/cert.pem", diff --git a/patches/config_expiration-mailer.patch b/patches/config_expiration-mailer.patch deleted file mode 100644 index 5df6e11..0000000 --- a/patches/config_expiration-mailer.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/test/config/expiration-mailer.json b/test/config/expiration-mailer.json -index 3b813060..6c709172 100644 ---- a/test/config/expiration-mailer.json -+++ b/test/config/expiration-mailer.json -@@ -16,6 +16,13 @@ - ], - "emailTemplate": "test/config/expiration-mailer.gotmpl", - "debugAddr": ":8008", -+ "dnsTries": 3, -+ "dnsStaticResolvers": [ -+ "127.0.0.1:8053", -+ "127.0.0.1:8054" -+ ], -+ "dnsTimeout": "3s", -+ "dnsAllowLoopbackAddresses": true, - "tls": { - "caCertFile": "test/certs/ipki/minica.pem", - "certFile": "test/certs/ipki/expiration-mailer.boulder/cert.pem", diff --git a/patches/config_notify-mailer.patch b/patches/config_notify-mailer.patch deleted file mode 100644 index 98238ce..0000000 --- a/patches/config_notify-mailer.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/test/config/notify-mailer.json b/test/config/notify-mailer.json -index f6813a696..115d5b150 100644 ---- a/test/config/notify-mailer.json -+++ b/test/config/notify-mailer.json -@@ -2,13 +2,22 @@ - "notifyMailer": { - "server": "localhost", - "port": "9380", -+ "hostnamePolicyFile": "test/hostname-policy.yaml", - "username": "cert-manager@example.com", - "passwordFile": "test/secrets/smtp_password", -+ "SMTPTrustedRootFile": "test/certs/ipki/minica.pem", - "db": { - "dbConnectFile": "test/secrets/mailer_dburl", - "maxOpenConns": 10 - } - }, -+ "pa": { -+ "challenges": { -+ "http-01": true, -+ "dns-01": true, -+ "tls-alpn-01": true -+ } -+ }, - "syslog": { - "stdoutLevel": 7, - "syslogLevel": 7 diff --git a/patches/config_ocsp-responder.patch b/patches/config_ocsp-responder.patch index f362609..7e962fa 100644 --- a/patches/config_ocsp-responder.patch +++ b/patches/config_ocsp-responder.patch @@ -1,5 +1,5 @@ diff --git a/test/config/ocsp-responder.json b/test/config/ocsp-responder.json -index c67aa41f7..92fe8a28f 100644 +index 1e5d4cb70..e56719c21 100644 --- a/test/config/ocsp-responder.json +++ b/test/config/ocsp-responder.json @@ -4,22 +4,6 @@ @@ -10,8 +10,8 @@ index c67aa41f7..92fe8a28f 100644 - "username": "ocsp-responder", - "passwordFile": "test/secrets/ocsp_responder_redis_password", - "shardAddrs": { -- "shard1": "10.33.33.2:4218", -- "shard2": "10.33.33.3:4218" +- "shard1": "10.77.77.2:4218", +- "shard2": "10.77.77.3:4218" - }, - "timeout": "5s", - "poolSize": 100, diff --git a/patches/config_ra.patch b/patches/config_ra.patch index 2e6b4ae..4dac21d 100644 --- a/patches/config_ra.patch +++ b/patches/config_ra.patch @@ -1,5 +1,5 @@ diff --git a/test/config/ra.json b/test/config/ra.json -index c16978e12..15e8252c0 100644 +index 613c5e1a1..c43053523 100644 --- a/test/config/ra.json +++ b/test/config/ra.json @@ -3,7 +3,8 @@ @@ -45,7 +45,7 @@ index c16978e12..15e8252c0 100644 ], "validationProfiles": { "legacy": { -@@ -58,9 +54,9 @@ +@@ -67,9 +63,9 @@ }, "defaultProfileName": "legacy", "tls": { @@ -58,7 +58,7 @@ index c16978e12..15e8252c0 100644 }, "vaService": { "dnsAuthority": "consul.service.consul", -@@ -154,7 +150,7 @@ +@@ -163,7 +159,7 @@ }, "ctLogs": { "stagger": "500ms", diff --git a/patches/contact-auditor_main.patch b/patches/contact-auditor_main.patch deleted file mode 100644 index 6b008d5..0000000 --- a/patches/contact-auditor_main.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/cmd/contact-auditor/main.go b/cmd/contact-auditor/main.go -index fdec0c660..cc62d91c0 100644 ---- a/cmd/contact-auditor/main.go -+++ b/cmd/contact-auditor/main.go -@@ -12,7 +12,9 @@ import ( - "time" - - "github.com/letsencrypt/boulder/cmd" -+ "github.com/letsencrypt/boulder/core" - "github.com/letsencrypt/boulder/db" -+ "github.com/letsencrypt/boulder/identifier" - blog "github.com/letsencrypt/boulder/log" - "github.com/letsencrypt/boulder/policy" - "github.com/letsencrypt/boulder/sa" -@@ -50,9 +52,16 @@ func validateContacts(id int64, createdAt string, contacts []string) error { - fmt.Fprintf(&probsBuff, "%d\t%s\tvalidation\t%q\t%q\t%q\n", id, createdAt, contact, prob, contacts) - } - -+ var pa *policy.AuthorityImpl -+ logger := cmd.NewLogger(cmd.SyslogConfig{StdoutLevel: 7}) -+ pa, _ = policy.New( -+ map[identifier.IdentifierType]bool{identifier.TypeDNS: true, identifier.TypeIP: true}, -+ map[core.AcmeChallenge]bool{}, -+ logger) -+ - for _, contact := range contacts { - if strings.HasPrefix(contact, "mailto:") { -- err := policy.ValidEmail(strings.TrimPrefix(contact, "mailto:")) -+ err := pa.ValidEmail(strings.TrimPrefix(contact, "mailto:")) - if err != nil { - writeProb(contact, err.Error()) - } diff --git a/patches/docker-compose.patch b/patches/docker-compose.patch index 32b305f..70317d1 100644 --- a/patches/docker-compose.patch +++ b/patches/docker-compose.patch @@ -1,5 +1,5 @@ diff --git a/docker-compose.yml b/docker-compose.yml -index 9b05172ef..e981e30ec 100644 +index 8092b1522..b9a8ac069 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,4 @@ @@ -8,9 +8,9 @@ index 9b05172ef..e981e30ec 100644 boulder: # The `letsencrypt/boulder-tools:latest` tag is automatically built in local @@ -14,13 +15,15 @@ services: - # to the IP address where your ACME client's solver is listening. - # FAKE_DNS: 172.17.0.1 - FAKE_DNS: 10.77.77.77 + # to the IP address where your ACME client's solver is listening. This is + # pointing at the boulder service's "public" IP, where challtestsrv is. + FAKE_DNS: 64.112.117.122 - BOULDER_CONFIG_DIR: test/config + BOULDER_CONFIG_DIR: labca/config GOCACHE: /boulder/.gocache/go-build @@ -26,7 +26,7 @@ index 9b05172ef..e981e30ec 100644 networks: bouldernet: ipv4_address: 10.77.77.77 -@@ -53,121 +56,138 @@ services: +@@ -53,122 +56,136 @@ services: - 4003:4003 # SFE depends_on: - bmysql @@ -66,7 +66,7 @@ index 9b05172ef..e981e30ec 100644 + restart: always bmysql: - image: mariadb:10.5 + image: mariadb:10.6.22 + volumes: + - dbdata:/var/lib/mysql networks: @@ -84,6 +84,12 @@ index 9b05172ef..e981e30ec 100644 + command: mysqld --bind-address=0.0.0.0 --log-output=TABLE logging: - driver: none ++ driver: "json-file" ++ options: ++ max-size: "500k" ++ max-file: "5" ++ restart: always + - bproxysql: - image: proxysql/proxysql:2.5.4 - # The --initial flag force resets the ProxySQL database on startup. By @@ -99,77 +105,62 @@ index 9b05172ef..e981e30ec 100644 - bouldernet: - aliases: - - boulder-proxysql -+ driver: "json-file" -+ options: -+ max-size: "500k" -+ max-file: "5" -+ restart: always - +- - bredis_1: + bredis: image: redis:6.2.7 volumes: -- - ./test/:/test/:cached + - ./test/:/test/:cached - command: redis-server /test/redis-ocsp.config -- networks: -- redisnet: -- ipv4_address: 10.33.33.2 -- ++ - /home/labca/boulder_labca:/opt/boulder/labca ++ command: redis-server /opt/boulder/labca/redis-ratelimits.config + networks: + bouldernet: +- # TODO(#8215): Remove this static IP allocation (and similar below) when +- # we tear down ocsp-responder. We only have it because ocsp-responder +- # requires IPs in its "ShardAddrs" config, while ratelimit redis +- # supports looking up shards via hostname and SRV record. +- ipv4_address: 10.77.77.2 ++ ipv4_address: 10.77.77.4 ++ restart: always + - bredis_2: - image: redis:6.2.7 -- volumes: ++ bconsul: ++ image: hashicorp/consul:1.15.4 ++ depends_on: ++ - control + volumes: - - ./test/:/test/:cached - command: redis-server /test/redis-ocsp.config -- networks: -- redisnet: -- ipv4_address: 10.33.33.3 -- ++ - /home/labca/boulder_labca:/opt/boulder/labca + networks: + bouldernet: +- ipv4_address: 10.77.77.3 ++ ipv4_address: 10.77.77.10 ++ command: "consul agent -dev -config-format=hcl -config-file=/opt/boulder/labca/consul/config.hcl" ++ restart: always + - bredis_3: - image: redis:6.2.7 - volumes: - - ./test/:/test/:cached - command: redis-server /test/redis-ratelimits.config -+ - /home/labca/boulder_labca:/opt/boulder/labca -+ command: redis-server /opt/boulder/labca/redis-ratelimits.config - networks: - redisnet: - ipv4_address: 10.33.33.4 -- -- bredis_4: -- image: redis:6.2.7 -- volumes: -- - ./test/:/test/:cached -- command: redis-server /test/redis-ratelimits.config -- networks: -- redisnet: -- ipv4_address: 10.33.33.5 -+ restart: always - - bconsul: - image: hashicorp/consul:1.15.4 -+ depends_on: -+ - control - volumes: -- - ./test/:/test/:cached -+ - /home/labca/boulder_labca:/opt/boulder/labca - networks: - consulnet: - ipv4_address: 10.55.55.10 - bouldernet: - ipv4_address: 10.77.77.10 -- command: "consul agent -dev -config-format=hcl -config-file=/test/consul/config.hcl" -+ command: "consul agent -dev -config-format=hcl -config-file=/opt/boulder/labca/consul/config.hcl" -+ restart: always - -- bjaeger: -- image: jaegertracing/all-in-one:1.50 + gui: + image: *boulder_tools_image networks: - bouldernet: -- ipv4_address: 10.77.77.17 +- ipv4_address: 10.77.77.4 +- +- bredis_4: +- image: redis:6.2.7 + - bouldernet -+ volumes: + volumes: +- - ./test/:/test/:cached +- command: redis-server /test/redis-ratelimits.config +- networks: +- bouldernet: +- ipv4_address: 10.77.77.5 + - /var/run/docker.sock:/var/run/docker.sock + - /home/labca/admin:/go/src/labca + - ./.gocache:/root/.cache/go-build @@ -191,11 +182,18 @@ index 9b05172ef..e981e30ec 100644 + max-size: "500k" + max-file: "5" + restart: always -+ + +- bconsul: +- image: hashicorp/consul:1.15.4 +- volumes: +- - ./test/:/test/:cached + nginx: + image: nginx:latest + restart: always -+ networks: + networks: +- bouldernet: +- ipv4_address: 10.77.77.10 +- command: "consul agent -dev -config-format=hcl -config-file=/test/consul/config.hcl" + - bouldernet + ports: + - 80:80 @@ -206,11 +204,13 @@ index 9b05172ef..e981e30ec 100644 + - /home/labca/nginx_data/static:/var/www/html + depends_on: + - control -+ + +- bjaeger: +- image: jaegertracing/all-in-one:1.50 + control: + image: *boulder_tools_image -+ networks: -+ - bouldernet + networks: + - bouldernet + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /home/labca/admin/data:/opt/labca/data @@ -236,12 +236,11 @@ index 9b05172ef..e981e30ec 100644 bpkimetal: image: ghcr.io/pkimetal/pkimetal:v1.20.0 networks: - bouldernet: - ipv4_address: 10.77.77.9 + - bouldernet + restart: always + +volumes: + dbdata: networks: - # This network is primarily used for boulder services. It is also used by + # This network represents the data-center internal network. It is used for diff --git a/patches/expiration-mailer_main.patch b/patches/expiration-mailer_main.patch deleted file mode 100644 index 383edab..0000000 --- a/patches/expiration-mailer_main.patch +++ /dev/null @@ -1,100 +0,0 @@ -diff --git a/cmd/expiration-mailer/main.go b/cmd/expiration-mailer/main.go -index 8c80c8408..4102e879b 100644 ---- a/cmd/expiration-mailer/main.go -+++ b/cmd/expiration-mailer/main.go -@@ -23,6 +23,7 @@ import ( - - "github.com/prometheus/client_golang/prometheus" - -+ "github.com/letsencrypt/boulder/bdns" - "github.com/letsencrypt/boulder/cmd" - "github.com/letsencrypt/boulder/config" - "github.com/letsencrypt/boulder/core" -@@ -40,7 +41,7 @@ import ( - ) - - const ( -- defaultExpirationSubject = "Let's Encrypt certificate expiration notice for domain {{.ExpirationSubject}}" -+ defaultExpirationSubject = "LabCA certificate expiration notice for domain {{.ExpirationSubject}}" - ) - - var ( -@@ -162,8 +163,12 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert - if parsed.Scheme != "mailto" { - continue - } -+ pa, err := policy.New(nil, nil, nil) -+ if err != nil { -+ return fmt.Errorf("cannot create policy authority implementation") -+ } - address := parsed.Opaque -- err = policy.ValidEmail(address) -+ err = pa.ValidEmail(address) - if err != nil { - m.log.Debugf("skipping invalid email: %s", err) - continue -@@ -697,10 +702,17 @@ type Config struct { - TLS cmd.TLSConfig - SAService *cmd.GRPCClientConfig - -+ DNSTries int -+ DNSStaticResolvers []string -+ DNSTimeout string -+ DNSAllowLoopbackAddresses bool -+ - // Path to a file containing a list of trusted root certificates for use - // during the SMTP connection (as opposed to the gRPC connections). - SMTPTrustedRootFile string - -+ UserAgent string -+ - Features features.Config - } - -@@ -850,8 +862,36 @@ func main() { - cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA") - sac := sapb.NewStorageAuthorityClient(conn) - -+ dnsTimeout, err := time.ParseDuration(c.Mailer.DNSTimeout) -+ cmd.FailOnError(err, "Couldn't parse DNS timeout") -+ dnsTries := c.Mailer.DNSTries -+ if dnsTries < 1 { -+ dnsTries = 1 -+ } -+ var resolver bdns.Client -+ servers, err := bdns.NewStaticProvider(c.Mailer.DNSStaticResolvers) -+ cmd.FailOnError(err, "Couldn't start static DNS server resolver") -+ if !c.Mailer.DNSAllowLoopbackAddresses { -+ r := bdns.New( -+ dnsTimeout, -+ servers, -+ scope, -+ clk, -+ dnsTries, -+ c.Mailer.UserAgent, -+ logger, -+ tlsConfig) -+ resolver = r -+ } else { -+ r := bdns.NewTest(dnsTimeout, servers, scope, clk, dnsTries, c.Mailer.UserAgent, logger, tlsConfig) -+ resolver = r -+ } -+ - var smtpRoots *x509.CertPool -- if c.Mailer.SMTPTrustedRootFile != "" { -+ smtpSkipVerify := false -+ if c.Mailer.SMTPTrustedRootFile == "InsecureSkipVerify" { -+ smtpSkipVerify = true -+ } else if c.Mailer.SMTPTrustedRootFile != "" { - pem, err := os.ReadFile(c.Mailer.SMTPTrustedRootFile) - cmd.FailOnError(err, "Loading trusted roots file") - smtpRoots = x509.NewCertPool() -@@ -885,6 +925,8 @@ func main() { - c.Mailer.Username, - smtpPassword, - smtpRoots, -+ smtpSkipVerify, -+ resolver, - *fromAddress, - logger, - scope, diff --git a/patches/mail_mailer.patch b/patches/mail_mailer.patch deleted file mode 100644 index 0cab39f..0000000 --- a/patches/mail_mailer.patch +++ /dev/null @@ -1,110 +0,0 @@ -diff --git a/mail/mailer.go b/mail/mailer.go -index 31ebd40b1..760b0b66e 100644 ---- a/mail/mailer.go -+++ b/mail/mailer.go -@@ -2,6 +2,7 @@ package mail - - import ( - "bytes" -+ "context" - "crypto/rand" - "crypto/tls" - "crypto/x509" -@@ -23,7 +24,9 @@ import ( - "github.com/jmhodges/clock" - "github.com/prometheus/client_golang/prometheus" - -+ "github.com/letsencrypt/boulder/bdns" - "github.com/letsencrypt/boulder/core" -+ berrors "github.com/letsencrypt/boulder/errors" - blog "github.com/letsencrypt/boulder/log" - ) - -@@ -139,6 +142,8 @@ func New( - username, - password string, - rootCAs *x509.CertPool, -+ insecureSkipVerify bool, -+ resolver bdns.Client, - from mail.Address, - logger blog.Logger, - stats prometheus.Registerer, -@@ -154,11 +159,13 @@ func New( - return &mailerImpl{ - config: config{ - dialer: &dialerImpl{ -- username: username, -- password: password, -- server: server, -- port: port, -- rootCAs: rootCAs, -+ username: username, -+ password: password, -+ server: server, -+ port: port, -+ rootCAs: rootCAs, -+ insecureSkipVerify: insecureSkipVerify, -+ dnsClient: resolver, - }, - log: logger, - from: from, -@@ -202,7 +209,7 @@ func (c config) generateMessage(to []string, subject, body string) ([]byte, erro - fmt.Sprintf("To: %s", strings.Join(addrs, ", ")), - fmt.Sprintf("From: %s", c.from.String()), - fmt.Sprintf("Subject: %s", subject), -- fmt.Sprintf("Date: %s", now.Format(time.RFC822)), -+ fmt.Sprintf("Date: %s", now.Format(time.RFC1123Z)), - fmt.Sprintf("Message-Id: <%s.%s.%s>", now.Format("20060102T150405"), mid.String(), c.from.Address), - "MIME-Version: 1.0", - "Content-Type: text/plain; charset=UTF-8", -@@ -259,23 +266,41 @@ func (m *mailerImpl) Connect() (Conn, error) { - type dialerImpl struct { - username, password, server, port string - rootCAs *x509.CertPool -+ insecureSkipVerify bool -+ dnsClient bdns.Client - } - - func (di *dialerImpl) Dial() (smtpClient, error) { -- hostport := net.JoinHostPort(di.server, di.port) -- var conn net.Conn -- var err error -- conn, err = tls.Dial("tcp", hostport, &tls.Config{ -- RootCAs: di.rootCAs, -- }) -+ deadline := time.Now().Add(30 * time.Second) -+ ctx, cancel := context.WithDeadline(context.Background(), deadline) -+ defer cancel() -+ -+ addrs, _, err := di.dnsClient.LookupHost(ctx, di.server) - if err != nil { -- return nil, err -+ problem := berrors.DNSError("%v") -+ return nil, problem -+ } -+ -+ if len(addrs) == 0 { -+ return nil, berrors.DNSError("No valid IP addresses found for %s", di.server) - } -- client, err := smtp.NewClient(conn, di.server) -+ -+ tlsconf := &tls.Config{ -+ ServerName: di.server, -+ } -+ if di.insecureSkipVerify { -+ tlsconf.InsecureSkipVerify = true -+ } else { -+ tlsconf.RootCAs = di.rootCAs -+ } -+ -+ hostport := net.JoinHostPort(addrs[0].String(), di.port) -+ client, err := smtp.Dial(hostport) - if err != nil { - return nil, err - } -- auth := smtp.PlainAuth("", di.username, di.password, di.server) -+ client.StartTLS(tlsconf) -+ auth := smtp.PlainAuth("", di.username, di.password, addrs[0].String()) - if err = client.Auth(auth); err != nil { - return nil, err - } diff --git a/patches/notify-mailer_main.patch b/patches/notify-mailer_main.patch deleted file mode 100644 index 279f29a..0000000 --- a/patches/notify-mailer_main.patch +++ /dev/null @@ -1,93 +0,0 @@ -diff --git a/cmd/notify-mailer/main.go b/cmd/notify-mailer/main.go -index 6c01efd64..6da77c7eb 100644 ---- a/cmd/notify-mailer/main.go -+++ b/cmd/notify-mailer/main.go -@@ -2,6 +2,7 @@ package notmain - - import ( - "context" -+ "crypto/x509" - "encoding/csv" - "encoding/json" - "errors" -@@ -37,6 +38,7 @@ type mailer struct { - recipients []recipient - targetRange interval - sleepInterval time.Duration -+ pa *policy.AuthorityImpl - parallelSends uint - } - -@@ -201,7 +203,7 @@ func (m *mailer) run(ctx context.Context) error { - continue - } - -- err := policy.ValidEmail(w.address) -+ err := m.pa.ValidEmail(w.address) - if err != nil { - m.log.Infof("Skipping %q due to policy violation: %s", w.address, err) - continue -@@ -502,7 +504,12 @@ type Config struct { - NotifyMailer struct { - DB cmd.DBConfig - cmd.SMTPConfig -+ // Path to a file containing a list of trusted root certificates for use -+ // during the SMTP connection (as opposed to the gRPC connections). -+ SMTPTrustedRootFile string -+ cmd.HostnamePolicyConfig - } -+ PA cmd.PAConfig - Syslog cmd.SyslogConfig - } - -@@ -570,6 +577,15 @@ func main() { - log.Infof("While reading the recipient list file %s", probs) - } - -+ // Validate PA config and set defaults if needed -+ cmd.FailOnError(cfg.PA.CheckChallenges(), "Invalid PA configuration") -+ -+ logger := cmd.NewLogger(cmd.SyslogConfig{StdoutLevel: 7}) -+ pa, err := policy.New(cfg.PA.Identifiers, cfg.PA.Challenges, logger) -+ cmd.FailOnError(err, "Failed to create PA") -+ err = pa.LoadHostnamePolicyFile(cfg.NotifyMailer.HostnamePolicyFile) -+ cmd.FailOnError(err, "Failed to load HostnamePolicyFile") -+ - var mailClient bmail.Mailer - if *dryRun { - log.Infof("Starting %s in dry-run mode", cmd.VersionString()) -@@ -579,11 +595,26 @@ func main() { - smtpPassword, err := cfg.NotifyMailer.PasswordConfig.Pass() - cmd.FailOnError(err, "Couldn't load SMTP password from file") - -+ var smtpRoots *x509.CertPool -+ smtpSkipVerify := false -+ if cfg.NotifyMailer.SMTPTrustedRootFile == "InsecureSkipVerify" { -+ smtpSkipVerify = true -+ } else if cfg.NotifyMailer.SMTPTrustedRootFile != "" { -+ pem, err := os.ReadFile(cfg.NotifyMailer.SMTPTrustedRootFile) -+ cmd.FailOnError(err, "Loading trusted roots file") -+ smtpRoots = x509.NewCertPool() -+ if !smtpRoots.AppendCertsFromPEM(pem) { -+ cmd.FailOnError(nil, "Failed to parse root certs PEM") -+ } -+ } -+ - mailClient = bmail.New( - cfg.NotifyMailer.Server, - cfg.NotifyMailer.Port, - cfg.NotifyMailer.Username, - smtpPassword, -+ smtpRoots, -+ smtpSkipVerify, - nil, - *address, - log, -@@ -605,6 +636,7 @@ func main() { - end: *end, - }, - sleepInterval: *sleep, -+ pa: pa, - parallelSends: *parallelSends, - } - diff --git a/patches/policy_pa.patch b/patches/policy_pa.patch index b0b5408..f8642bd 100644 --- a/patches/policy_pa.patch +++ b/patches/policy_pa.patch @@ -1,8 +1,8 @@ diff --git a/policy/pa.go b/policy/pa.go -index 661a6b6bc..17dde317f 100644 +index f53100322..107c5986e 100644 --- a/policy/pa.go +++ b/policy/pa.go -@@ -32,6 +32,9 @@ type AuthorityImpl struct { +@@ -31,6 +31,9 @@ type AuthorityImpl struct { blocklist map[string]bool exactBlocklist map[string]bool wildcardExactBlocklist map[string]bool @@ -12,7 +12,7 @@ index 661a6b6bc..17dde317f 100644 blocklistMu sync.RWMutex enabledChallenges map[core.AcmeChallenge]bool -@@ -75,6 +78,10 @@ type blockedNamesPolicy struct { +@@ -66,6 +69,10 @@ type blockedNamesPolicy struct { // time above and beyond the high-risk domains. Managing these entries separately // from HighRiskBlockedNames makes it easier to vet changes accurately. AdminBlockedNames []string `yaml:"AdminBlockedNames"` @@ -23,7 +23,7 @@ index 661a6b6bc..17dde317f 100644 } // LoadHostnamePolicyFile will load the given policy file, returning an error if -@@ -134,10 +141,21 @@ func (pa *AuthorityImpl) processHostnamePolicy(policy blockedNamesPolicy) error +@@ -125,10 +132,21 @@ func (pa *AuthorityImpl) processHostnamePolicy(policy blockedNamesPolicy) error // wildcardNameMap to block issuance for `*.`+parts[1] wildcardNameMap[parts[1]] = true } @@ -45,7 +45,7 @@ index 661a6b6bc..17dde317f 100644 pa.blocklistMu.Unlock() return nil } -@@ -209,7 +227,7 @@ var ( +@@ -199,7 +217,7 @@ var ( // - exactly equal to an IANA registered TLD // // It does NOT ensure that the domain is absent from any PA blocked lists. @@ -54,7 +54,7 @@ index 661a6b6bc..17dde317f 100644 if domain == "" { return errEmptyIdentifier } -@@ -241,7 +259,9 @@ func validNonWildcardDomain(domain string) error { +@@ -232,7 +250,9 @@ func validNonWildcardDomain(domain string) error { return errTooManyLabels } if len(labels) < 2 { @@ -65,7 +65,7 @@ index 661a6b6bc..17dde317f 100644 } for _, label := range labels { // Check that this is a valid LDH Label: "A string consisting of ASCII -@@ -285,6 +305,14 @@ func validNonWildcardDomain(domain string) error { +@@ -276,6 +296,14 @@ func validNonWildcardDomain(domain string) error { } } @@ -80,7 +80,7 @@ index 661a6b6bc..17dde317f 100644 // Names must end in an ICANN TLD, but they must not be equal to an ICANN TLD. icannTLD, err := iana.ExtractSuffix(domain) if err != nil { -@@ -300,9 +328,9 @@ func validNonWildcardDomain(domain string) error { +@@ -291,9 +319,9 @@ func validNonWildcardDomain(domain string) error { // ValidDomain checks that a domain is valid and that it doesn't contain any // invalid wildcard characters. It does NOT ensure that the domain is absent // from any PA blocked lists. @@ -92,7 +92,7 @@ index 661a6b6bc..17dde317f 100644 } // Names containing more than one wildcard are invalid. -@@ -321,7 +349,7 @@ func ValidDomain(domain string) error { +@@ -312,7 +340,7 @@ func ValidDomain(domain string) error { // Names must end in an ICANN TLD, but they must not be equal to an ICANN TLD. icannTLD, err := iana.ExtractSuffix(baseDomain) @@ -101,7 +101,7 @@ index 661a6b6bc..17dde317f 100644 return errNonPublic } // Names must have a non-wildcard label immediately adjacent to the ICANN -@@ -329,7 +357,7 @@ func ValidDomain(domain string) error { +@@ -320,7 +348,7 @@ func ValidDomain(domain string) error { if baseDomain == icannTLD { return errICANNTLDWildcard } @@ -109,8 +109,8 @@ index 661a6b6bc..17dde317f 100644 + return pa.ValidNonWildcardDomain(baseDomain, false) } - // validIP checks that an IP address: -@@ -375,14 +403,14 @@ var forbiddenMailDomains = map[string]bool{ + // ValidIP checks that an IP address: +@@ -363,14 +391,14 @@ var forbiddenMailDomains = map[string]bool{ // ValidEmail returns an error if the input doesn't parse as an email address, // the domain isn't a valid hostname in Preferred Name Syntax, or its on the // list of domains forbidden for mail (because they are often used in examples). @@ -127,7 +127,7 @@ index 661a6b6bc..17dde317f 100644 if err != nil { return berrors.InvalidEmailError("contact email has invalid domain: %s", err) } -@@ -424,7 +452,7 @@ func subError(ident identifier.ACMEIdentifier, err error) berrors.SubBoulderErro +@@ -412,7 +440,7 @@ func subError(ident identifier.ACMEIdentifier, err error) berrors.SubBoulderErro // // Precondition: all input identifier values must be in lowercase. func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error { @@ -136,7 +136,7 @@ index 661a6b6bc..17dde317f 100644 if err != nil { return err } -@@ -454,6 +482,10 @@ func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error +@@ -442,6 +470,10 @@ func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error } } @@ -147,7 +147,7 @@ index 661a6b6bc..17dde317f 100644 // For both wildcard and non-wildcard domains, check whether any parent domain // name is on the regular blocklist. err := pa.checkHostLists(ident.Value) -@@ -494,12 +526,12 @@ func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error +@@ -483,12 +515,12 @@ func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error // // If multiple identifiers are invalid, the error will contain suberrors // specific to each identifier. @@ -162,7 +162,7 @@ index 661a6b6bc..17dde317f 100644 if err != nil { subErrors = append(subErrors, subError(ident, err)) } -@@ -541,6 +573,34 @@ func combineSubErrors(subErrors []berrors.SubBoulderError) error { +@@ -530,6 +562,34 @@ func combineSubErrors(subErrors []berrors.SubBoulderError) error { return nil } @@ -197,7 +197,7 @@ index 661a6b6bc..17dde317f 100644 // checkWildcardHostList checks the wildcardExactBlocklist for a given domain. // If the domain is not present on the list nil is returned, otherwise // errPolicyForbidden is returned. -@@ -570,6 +630,9 @@ func (pa *AuthorityImpl) checkHostLists(domain string) error { +@@ -559,6 +619,9 @@ func (pa *AuthorityImpl) checkHostLists(domain string) error { labels := strings.Split(domain, ".") for i := range labels { joined := strings.Join(labels[i:], ".") diff --git a/patches/ra_ra.patch b/patches/ra_ra.patch index d340ae1..e4434b3 100644 --- a/patches/ra_ra.patch +++ b/patches/ra_ra.patch @@ -1,5 +1,5 @@ diff --git a/ra/ra.go b/ra/ra.go -index e8acf0781..3122449be 100644 +index ba993179a..04aec2370 100644 --- a/ra/ra.go +++ b/ra/ra.go @@ -44,7 +44,6 @@ import ( @@ -10,7 +10,7 @@ index e8acf0781..3122449be 100644 "github.com/letsencrypt/boulder/probs" pubpb "github.com/letsencrypt/boulder/publisher/proto" rapb "github.com/letsencrypt/boulder/ra/proto" -@@ -608,7 +607,7 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error { +@@ -574,7 +573,7 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error { if !core.IsASCII(contact) { return berrors.InvalidEmailError("contact email contains non-ASCII characters") } @@ -19,7 +19,7 @@ index e8acf0781..3122449be 100644 if err != nil { return err } -@@ -1981,6 +1980,9 @@ func crlShard(cert *x509.Certificate) (int64, error) { +@@ -1895,6 +1894,9 @@ func crlShard(cert *x509.Certificate) (int64, error) { return 0, fmt.Errorf("malformed CRLDistributionPoint %q", url) } shardStr := url[lastIndex+1:] diff --git a/patches/ratelimits_names.patch b/patches/ratelimits_names.patch index a9bc69b..8f5a5f9 100644 --- a/patches/ratelimits_names.patch +++ b/patches/ratelimits_names.patch @@ -1,8 +1,8 @@ diff --git a/ratelimits/names.go b/ratelimits/names.go -index bfda772b5..971892f22 100644 +index 1ce3c514c..6f72b517c 100644 --- a/ratelimits/names.go +++ b/ratelimits/names.go -@@ -102,6 +102,9 @@ var nameToString = map[Name]string{ +@@ -114,6 +114,9 @@ var nameToString = map[Name]string{ FailedAuthorizationsForPausingPerDomainPerAccount: "FailedAuthorizationsForPausingPerDomainPerAccount", } @@ -12,53 +12,54 @@ index bfda772b5..971892f22 100644 // isValid returns true if the Name is a valid rate limit name. func (n Name) isValid() bool { return n > Unknown && n < Name(len(nameToString)) -@@ -163,7 +166,15 @@ func validateRegId(id string) error { - // validateDomain validates that the provided string is formatted 'domain', - // where domain is a domain name. - func validateDomain(id string) error { -- err := policy.ValidDomain(id) +@@ -195,7 +198,14 @@ func validateRegIdIdentValue(id string) error { + return fmt.Errorf( + "invalid regId, %q must be formatted 'regId:identValue'", id) + } +- domainErr := policy.ValidDomain(regIdIdentValue[1]) ++ pa := PA ++ if pa == nil { ++ pa, err = policy.New(map[identifier.IdentifierType]bool{"dns": true}, nil, nil) ++ if err != nil { ++ return fmt.Errorf("cannot create policy authority implementation") ++ } ++ } ++ domainErr := pa.ValidDomain(regIdIdentValue[1]) + if domainErr != nil { + ipErr := policy.ValidIP(regIdIdentValue[1]) + if ipErr != nil { +@@ -209,7 +219,15 @@ func validateRegIdIdentValue(id string) error { + // name or an IP address. IPv6 addresses must be the lowest address in their + // /64, i.e. their last 64 bits must be zero. + func validateDomainOrCIDR(limit Name, id string) error { +- domainErr := policy.ValidDomain(id) + pa := PA + var err error + if pa == nil { -+ pa, err = policy.New(nil, nil, nil) ++ pa, err = policy.New(map[identifier.IdentifierType]bool{"dns": true}, nil, nil) + if err != nil { + return fmt.Errorf("cannot create policy authority implementation") + } + } -+ err = pa.ValidDomain(id) - if err != nil { - return fmt.Errorf("invalid domain, %q must be formatted 'domain': %w", id, err) - } -@@ -184,7 +195,14 @@ func validateRegIdDomain(id string) error { - return fmt.Errorf( - "invalid regId, %q must be formatted 'regId:domain'", id) - } -- err = policy.ValidDomain(regIdDomain[1]) -+ pa := PA -+ if pa == nil { -+ pa, err = policy.New(nil, nil, nil) -+ if err != nil { -+ return fmt.Errorf("cannot create policy authority implementation") -+ } -+ } -+ err = pa.ValidDomain(regIdDomain[1]) - if err != nil { - return fmt.Errorf( - "invalid domain, %q must be formatted 'regId:domain': %w", id, err) -@@ -202,7 +220,15 @@ func validateFQDNSet(id string) error { ++ domainErr := pa.ValidDomain(id) + if domainErr == nil { + // This is a valid domain. + return nil +@@ -264,8 +282,16 @@ func validateFQDNSet(id string) error { return fmt.Errorf( "invalid fqdnSet, %q must be formatted 'fqdnSet'", id) } -- return policy.WellFormedIdentifiers(identifier.NewDNSSlice(domains)) -+ pa := PA + var err error ++ pa := PA + if pa == nil { -+ pa, err = policy.New(nil, nil, nil) ++ pa, err = policy.New(map[identifier.IdentifierType]bool{"dns": true}, nil, nil) + if err != nil { + return fmt.Errorf("cannot create policy authority implementation") + } + } -+ return pa.WellFormedIdentifiers(identifier.NewDNSSlice(domains)) - } - - func validateIdForName(name Name, id string) error { + for _, value := range values { +- domainErr := policy.ValidDomain(value) ++ domainErr := pa.ValidDomain(value) + if domainErr != nil { + ipErr := policy.ValidIP(value) + if ipErr != nil { diff --git a/patches/remoteva_main.patch b/patches/remoteva_main.patch index 47aa8ff..17fae1f 100644 --- a/patches/remoteva_main.patch +++ b/patches/remoteva_main.patch @@ -1,8 +1,8 @@ diff --git a/cmd/remoteva/main.go b/cmd/remoteva/main.go -index f99ded497..9a1033a87 100644 +index f4c0cbe76..1f454f489 100644 --- a/cmd/remoteva/main.go +++ b/cmd/remoteva/main.go -@@ -56,7 +56,8 @@ type Config struct { +@@ -57,7 +57,8 @@ type Config struct { // For more information, see: https://pkg.go.dev/crypto/tls#ClientAuthType SkipGRPCClientCertVerification bool @@ -12,12 +12,30 @@ index f99ded497..9a1033a87 100644 } Syslog cmd.SyslogConfig -@@ -141,7 +142,8 @@ func main() { +@@ -87,12 +88,16 @@ func main() { + clk := cmd.Clock() + + var servers bdns.ServerProvider ++ proto := "udp" ++ if features.Get().DOH { ++ proto = "tcp" ++ } + + if len(c.RVA.DNSStaticResolvers) != 0 { + servers, err = bdns.NewStaticProvider(c.RVA.DNSStaticResolvers) + cmd.FailOnError(err, "Couldn't start static DNS server resolver") + } else { +- servers, err = bdns.StartDynamicProvider(c.RVA.DNSProvider, 60*time.Second, "tcp") ++ servers, err = bdns.StartDynamicProvider(c.RVA.DNSProvider, 60*time.Second, proto) + cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver") + } + defer servers.Stop() +@@ -138,7 +143,8 @@ func main() { c.RVA.AccountURIPrefixes, c.RVA.Perspective, c.RVA.RIR, -- bdns.IsReservedIP) -+ bdns.IsReservedIP, +- iana.IsReservedAddr) ++ iana.IsReservedAddr, + c.RVA.LabCADomains) cmd.FailOnError(err, "Unable to create Remote-VA server") diff --git a/patches/reversed-hostname-checker_main.patch b/patches/reversed-hostname-checker_main.patch new file mode 100644 index 0000000..9d1d046 --- /dev/null +++ b/patches/reversed-hostname-checker_main.patch @@ -0,0 +1,13 @@ +diff --git a/cmd/reversed-hostname-checker/main.go b/cmd/reversed-hostname-checker/main.go +index 530dd7ca3..1235258ba 100644 +--- a/cmd/reversed-hostname-checker/main.go ++++ b/cmd/reversed-hostname-checker/main.go +@@ -41,7 +41,7 @@ func main() { + scanner := bufio.NewScanner(input) + logger := cmd.NewLogger(cmd.SyslogConfig{StdoutLevel: 7}) + logger.Info(cmd.VersionString()) +- pa, err := policy.New(nil, nil, logger) ++ pa, err := policy.New(map[identifier.IdentifierType]bool{"dns": true}, nil, logger) + if err != nil { + log.Fatal(err) + } diff --git a/patches/test_config_ca.patch b/patches/test_config_ca.patch index 50f2879..9fea312 100644 --- a/patches/test_config_ca.patch +++ b/patches/test_config_ca.patch @@ -1,5 +1,5 @@ diff --git a/test/config/ca.json b/test/config/ca.json -index 35843b094..2d4e0c951 100644 +index e9a866ee6..e44b75aed 100644 --- a/test/config/ca.json +++ b/test/config/ca.json @@ -1,11 +1,11 @@ @@ -139,7 +139,7 @@ index 35843b094..2d4e0c951 100644 "features": {} }, "pa": { -@@ -194,7 +137,7 @@ +@@ -197,7 +140,7 @@ } }, "syslog": { diff --git a/patches/va_http.patch b/patches/va_http.patch index 7fdf5e2..2473192 100644 --- a/patches/va_http.patch +++ b/patches/va_http.patch @@ -1,8 +1,8 @@ diff --git a/va/http.go b/va/http.go -index 00942ede3..2b4ece730 100644 +index e7b0ec304..2b2aa2210 100644 --- a/va/http.go +++ b/va/http.go -@@ -341,7 +341,16 @@ func (va *ValidationAuthorityImpl) extractRequestTarget(req *http.Request) (iden +@@ -350,7 +350,16 @@ func (va *ValidationAuthorityImpl) extractRequestTarget(req *http.Request) (iden } if _, err := iana.ExtractSuffix(reqHost); err != nil { @@ -20,3 +20,18 @@ index 00942ede3..2b4ece730 100644 } return identifier.NewDNS(reqHost), reqPort, nil +@@ -398,10 +407,10 @@ func (va *ValidationAuthorityImpl) setupHTTPValidation( + + // This is a backstop check to avoid connecting to reserved IP addresses. + // They should have been caught and excluded by `bdns.LookupHost`. +- err := va.isReservedIPFunc(targetIP) +- if err != nil { +- return nil, record, err +- } ++ // err := va.isReservedIPFunc(targetIP) ++ // if err != nil { ++ // return nil, record, err ++ // } + + record.AddressUsed = targetIP + diff --git a/patches/va_va.patch b/patches/va_va.patch index 816079d..fe43612 100644 --- a/patches/va_va.patch +++ b/patches/va_va.patch @@ -1,24 +1,24 @@ diff --git a/va/va.go b/va/va.go -index 5e7732d69..9a908c255 100644 +index 4307e57b4..c63b2dea8 100644 --- a/va/va.go +++ b/va/va.go -@@ -217,6 +217,7 @@ type ValidationAuthorityImpl struct { +@@ -218,6 +218,7 @@ type ValidationAuthorityImpl struct { perspective string rir string - isReservedIPFunc func(ip net.IP) bool + isReservedIPFunc func(netip.Addr) error + labcaDomains []string metrics *vaMetrics } -@@ -237,6 +238,7 @@ func NewValidationAuthorityImpl( +@@ -238,6 +239,7 @@ func NewValidationAuthorityImpl( perspective string, rir string, - reservedIPChecker func(ip net.IP) bool, + reservedIPChecker func(netip.Addr) error, + labcaDomains []string, ) (*ValidationAuthorityImpl, error) { if len(accountURIPrefixes) == 0 { -@@ -274,6 +276,7 @@ func NewValidationAuthorityImpl( +@@ -275,6 +277,7 @@ func NewValidationAuthorityImpl( perspective: perspective, rir: rir, isReservedIPFunc: reservedIPChecker, diff --git a/patches/wfe2_main.patch b/patches/wfe2_main.patch index b829821..2386460 100644 --- a/patches/wfe2_main.patch +++ b/patches/wfe2_main.patch @@ -1,5 +1,5 @@ diff --git a/cmd/boulder-wfe2/main.go b/cmd/boulder-wfe2/main.go -index 1f33c4746..1b0ad2ddb 100644 +index 955fe406c..33cc238d9 100644 --- a/cmd/boulder-wfe2/main.go +++ b/cmd/boulder-wfe2/main.go @@ -12,14 +12,17 @@ import ( @@ -29,7 +29,7 @@ index 1f33c4746..1b0ad2ddb 100644 // DirectoryWebsite is used for the /directory response's "meta" element's // "website" field. DirectoryWebsite string `validate:"required,url"` -@@ -175,6 +178,8 @@ type Config struct { +@@ -180,6 +183,8 @@ type Config struct { // to enable the pausing feature. URL string `validate:"omitempty,required_with=HMACKey JWTLifetime,url,startswith=https://,endsnotwith=/"` } @@ -38,7 +38,7 @@ index 1f33c4746..1b0ad2ddb 100644 } Syslog cmd.SyslogConfig -@@ -315,11 +320,25 @@ func main() { +@@ -324,11 +329,25 @@ func main() { var limiter *ratelimits.Limiter var txnBuilder *ratelimits.TransactionBuilder var limiterRedis *bredis.Ring @@ -64,7 +64,7 @@ index 1f33c4746..1b0ad2ddb 100644 source := ratelimits.NewRedisSource(limiterRedis.Ring, clk, stats) limiter, err = ratelimits.NewLimiter(clk, source, stats) cmd.FailOnError(err, "Failed to create rate limiter") -@@ -359,6 +378,7 @@ func main() { +@@ -369,6 +388,7 @@ func main() { unpauseSigner, c.WFE.Unpause.JWTLifetime.Duration, c.WFE.Unpause.URL, diff --git a/patches/wfe2_wfe.patch b/patches/wfe2_wfe.patch index be6f0e3..eb822d6 100644 --- a/patches/wfe2_wfe.patch +++ b/patches/wfe2_wfe.patch @@ -1,8 +1,8 @@ diff --git a/wfe2/wfe.go b/wfe2/wfe.go -index 462866a1d..287e6af55 100644 +index 891d165b6..1a4fda298 100644 --- a/wfe2/wfe.go +++ b/wfe2/wfe.go -@@ -163,6 +163,8 @@ type WebFrontEndImpl struct { +@@ -166,6 +166,8 @@ type WebFrontEndImpl struct { // descriptions (perhaps including URLs) of those profiles. NewOrder // Requests with a profile name not present in this map will be rejected. certProfiles map[string]string @@ -11,7 +11,7 @@ index 462866a1d..287e6af55 100644 } // NewWebFrontEndImpl constructs a web service for Boulder -@@ -188,6 +190,7 @@ func NewWebFrontEndImpl( +@@ -192,6 +194,7 @@ func NewWebFrontEndImpl( unpauseSigner unpause.JWTSigner, unpauseJWTLifetime time.Duration, unpauseURL string, @@ -19,7 +19,7 @@ index 462866a1d..287e6af55 100644 ) (WebFrontEndImpl, error) { if len(issuerCertificates) == 0 { return WebFrontEndImpl{}, errors.New("must provide at least one issuer certificate") -@@ -205,6 +208,10 @@ func NewWebFrontEndImpl( +@@ -209,6 +212,10 @@ func NewWebFrontEndImpl( return WebFrontEndImpl{}, errors.New("must provide a service for nonce redemption") } @@ -30,7 +30,7 @@ index 462866a1d..287e6af55 100644 wfe := WebFrontEndImpl{ log: logger, clk: clk, -@@ -227,6 +234,7 @@ func NewWebFrontEndImpl( +@@ -232,6 +239,7 @@ func NewWebFrontEndImpl( unpauseSigner: unpauseSigner, unpauseJWTLifetime: unpauseJWTLifetime, unpauseURL: unpauseURL, @@ -38,34 +38,16 @@ index 462866a1d..287e6af55 100644 } return wfe, nil -@@ -635,7 +643,7 @@ func link(url, relation string) string { - // contactsToEmails converts a *[]string of contacts (e.g. mailto: - // person@example.com) to a []string of valid email addresses. Non-email - // contacts or contacts with invalid email addresses are ignored. --func contactsToEmails(contacts *[]string) []string { -+func contactsToEmails(contacts *[]string, pa *policy.AuthorityImpl) []string { - if contacts == nil { - return nil - } -@@ -645,7 +653,7 @@ func contactsToEmails(contacts *[]string) []string { - continue +@@ -678,7 +686,7 @@ func (wfe *WebFrontEndImpl) contactsToEmails(contacts []string) ([]string, error + return nil, berrors.InvalidEmailError("contact email contains non-ASCII characters") } - address := strings.TrimPrefix(c, "mailto:") -- err := policy.ValidEmail(address) -+ err := pa.ValidEmail(address) - if err != nil { - continue - } -@@ -869,7 +877,7 @@ func (wfe *WebFrontEndImpl) NewAccount( - } - newRegistrationSuccessful = true -- emails := contactsToEmails(accountCreateRequest.Contact) -+ emails := contactsToEmails(accountCreateRequest.Contact, wfe.pa) - if wfe.ee != nil && len(emails) > 0 { - _, err := wfe.ee.SendContacts(ctx, &emailpb.SendContactsRequest{ - // Note: We are explicitly using the contacts provided by the -@@ -2300,7 +2308,7 @@ func (wfe *WebFrontEndImpl) NewOrder( +- err = policy.ValidEmail(parsed.Opaque) ++ err = wfe.pa.ValidEmail(parsed.Opaque) + if err != nil { + return nil, err + } +@@ -2299,7 +2307,7 @@ func (wfe *WebFrontEndImpl) NewOrder( idents = identifier.Normalize(idents) logEvent.Identifiers = idents