{"id":47762753,"url":"https://github.com/taskcluster/stateless-dns-server","last_synced_at":"2026-04-03T05:49:08.284Z","repository":{"id":28249220,"uuid":"31756121","full_name":"taskcluster/stateless-dns-server","owner":"taskcluster","description":"Stateless DNS server with IP, expiration and signature encoded in sub-domain labels","archived":false,"fork":false,"pushed_at":"2025-06-06T13:39:57.000Z","size":82,"stargazers_count":4,"open_issues_count":1,"forks_count":4,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-10-25T21:33:12.438Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/taskcluster.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-06T06:38:19.000Z","updated_at":"2025-06-06T13:39:54.000Z","dependencies_parsed_at":"2022-09-04T13:10:24.432Z","dependency_job_id":null,"html_url":"https://github.com/taskcluster/stateless-dns-server","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/taskcluster/stateless-dns-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taskcluster%2Fstateless-dns-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taskcluster%2Fstateless-dns-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taskcluster%2Fstateless-dns-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taskcluster%2Fstateless-dns-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taskcluster","download_url":"https://codeload.github.com/taskcluster/stateless-dns-server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taskcluster%2Fstateless-dns-server/sbom","scorecard":{"id":869264,"data":{"date":"2025-08-11","repo":{"name":"github.com/taskcluster/stateless-dns-server","commit":"4cd703ccb90aaaccdcf627896f4a34710e692e04"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":4,"reason":"5 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":2,"reason":"Found 5/18 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Mozilla Public License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1","Warn: containerImage not pinned by hash: Dockerfile:11: pin your Docker image by updating node:22-alpine to node:22-alpine@sha256:1b2479dd35a99687d6638f5976fd235e26c5b37e8122f786fcd5fe231d63de5b","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/taskcluster/.github/SECURITY.md:1","Info: Found linked content: github.com/taskcluster/.github/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/taskcluster/.github/SECURITY.md:1","Info: Found text in security policy: github.com/taskcluster/.github/SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":6,"reason":"4 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-2j2x-2gpw-g8fm","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T03:39:05.226Z","repository_id":28249220,"created_at":"2025-08-24T03:39:05.226Z","updated_at":"2025-08-24T03:39:05.226Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31337184,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T04:42:29.251Z","status":"ssl_error","status_checked_at":"2026-04-03T04:42:12.667Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-03T05:49:08.119Z","updated_at":"2026-04-03T05:49:08.267Z","avatar_url":"https://github.com/taskcluster.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Stateless DNS Server [![Circle CI](https://circleci.com/gh/taskcluster/stateless-dns-server.svg?style=badge)](https://circleci.com/gh/taskcluster/stateless-dns-server)\n====================\nThis is a stateless DNS server that returns `A` records for sub-domains, where\nthe sub-domain label encodes the IP-address, expiration date, a random salt and\nan HMAC-SHA256 signature truncated to 128 bits.\n\nThis is allows for assigning temporary sub-domains names to nodes with a public\nIP-address. The same problem can also be solved with dynamic DNS server, but\nsuch entries often requires clean-up. The beauty of this approach is that the\nDNS server is state-less, so there is no stale DNS records to discard.\n\nIn TaskCluster this is used to assign temporary sub-domain names to EC2 spot\nnodes, such that we can host HTTPS resources, such as live logs, without\nupdating and cleaning up the state of the DNS server.\n\nNotice, that with IP-address, expiration date, random salt and HMAC-SHA256\nsignature encoded in the sub-domain label, you cannot decide which sub-domain\nlabel you wish to have. Hence, this is only useful in cases were the hostname\nfor your node is transmitted to clients by other means, for example in a message\nover RabbitMQ or as temporary entry in a database. Further more, to serve HTTPS\ncontent you'll need a wild-card SSL certificate, for domain managed by this\nDNS server.\n\nNote, this obviously doesn't have many applications, as the sub-domain label\nis stateful. It's mostly for serving HTTPS content from nodes that come and go\nquickly with minimal setup, where the hostname is transmitted by other means.\nGenerally, any case where you might consider using the default EC2 hostname.\n\nSub-domain Label Generation\n---------------------------\nThe sub-domain label encodes the following parameters:\n * `ip`, address to which the `A` record returned should point,\n * `expires`, expiration of sub-domain as number of ms since epoch,\n * `salt`, random salt, allowing for generation of multiple sub-domain labels\n    for each IP-address, and,\n * `signature`, HMAC-SHA256 signature of `ip`, `expires` and `salt` truncated\n    to 128 bit.\n\nThe `expires` property is encoded as a big-endian 64 bit signed integer. The\n`salt` property is encoded as bit-endian 16 bit unsigned integer. All properties\nare concatenated and base32 (RFC 3548) encoded to form the sub-domain label.\n\nExample pseudo code:\n```\n  ip        = a.b.c.d\n  expires   = Date.now() + number of ms to expiration\n  salt      = random 16 bit integer\n  signature = HMAC-SHA256(ip + expires + salt).slice(0, 16);\n  label     = ip + expires + salt + signature\n  hostname  = label + '.' + DOMAIN\n```\n\nYou can also load this npm package as a library and use it to generate\nsub-domain labels. See example below:\n```js\nvar statelessDNSServer = require('stateless-dns-server');\n\nvar ip        = [127, 0, 0, 1];\nvar expires   = new Date(Date.now() + 10 * 60 * 1000);   // 10 minutes\nvar secret    = '...';  // 256 bit randomness recommended\nvar domain    = 'taskcluster-worker.net';\nvar hostname  = statelessDNSServer.createHostname(ip, expires, secret, domain);\nconsole.log(hostname);\n// out: miy6hl7234h3kcycsqfhrxgnltaa2oc4owdlo5bnvbpa5mzd.taskcluster-worker.net\n```\n\nThe resulting `hostname` in the example above will resolved to `127.0.0.1` for\nthe next 10 minutes, after which only cached DNS entries may stick around,\ndepend on the configured `TTL`.\n\nConfiguration\n-------------\nThe docker image takes the following environment variables for configuration.\n * `PORT`, port to host DNS server on (defaults to `55553`),\n * `TTL`, time-to-live for DNS records returned in seconds (defaults to `600`),\n * `DOMAIN`, domain under which to manage sub-domains (**required**), and\n * `PRIMARY_SECRET`, secret token for HMAC-SHA256 signature generation (**required**).\n * `SECONDARY_SECRET`, secret token for HMAC-SHA256 signature generation.\n(The server supports two secrets primary and secondary to support rotation).\n* `TXT_RECORDS`, list of static responses for pre-defined hostnames and record types,\nfor example: `{\".\": \"some TXT response for the root domain\", \"_subdomain\": \"TXT response for subdomain\"}`\n\nDevelopment \u0026 Deployment\n------------------------\nAs usual `npm test` will run tests over localhost. For deployment you can\nbuild a docker image that is easy to deploy. There is a very simple makefile in\nthis repository with the following targets. You can set the environment variable\n`REGISTRY` to overwrite the default registry.\n\n * `make image`, build docker image\n * `make test`, test docker image with `DOMAIN=test-domain.local` and\n    `PRIMARY_SECRET=no-secret` running on port `55553` of localhost.\n * `make push`, push the image to registry.\n\nWhen running locally you can test the response from the DNS server using `dig`\nunder Linux. For example `dig @localhost -p 55553 \u003clabel\u003e.test-domain.local`.\nThis is useful before deploying, or just after deployment to verify that\neverything works.\n\nReporting Issues\n----------------\nIssues should be reported under the under the [Taskcluster :: Services component at bugzilla.mozilla.org](https://bugzilla.mozilla.org/enter_bug.cgi?product=Taskcluster\u0026component=Services).\nView issues with this [saved search](https://bugzilla.mozilla.org/buglist.cgi?short_desc=dns\u0026query_format=advanced\u0026short_desc_type=allwordssubstr\u0026product=TaskCluster\u0026resolution=---https://bugzilla.mozilla.org/buglist.cgi?short_desc=dns\u0026query_format=advanced\u0026short_desc_type=allwordssubstr\u0026product=TaskCluster\u0026resolution=---\u0026list_id=15212521).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaskcluster%2Fstateless-dns-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaskcluster%2Fstateless-dns-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaskcluster%2Fstateless-dns-server/lists"}