getreadystack's picture
Upload index.html with huggingface_hub
af17654 verified
Raw History Blame Contribute Delete
39.1 kB
<!doctype html><html lang="en"><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>TLS Cert Lifetime Lint - SC-081v3 renewal check</title>
<meta name="description" content="Finds the 12 settings that break when public TLS certificates fall to 100 days on 2027-03-15: openssl -days, Terraform, cert-manager, late expiry alerts, HPKP, TLS 1.0/1.1, SHA-1, RSA-1024.">
<style>
:root{color-scheme:light dark}
body{margin:0;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
background:#fbfbfa;color:#16161d}
@media(prefers-color-scheme:dark){body{background:#14141a;color:#e8e8ea}}
.wrap{max-width:880px;margin:0 auto;padding:28px 20px 64px}
h1{font-size:1.7rem;line-height:1.25;margin:.2em 0 .3em}
p.sub{margin:0 0 1.4em;opacity:.8}
textarea{width:100%;min-height:230px;font:13px/1.5 ui-monospace,Menlo,Consolas,monospace;
padding:12px;border:1px solid #c9c9d1;border-radius:10px;background:transparent;color:inherit;
box-sizing:border-box}
button{font:600 15px/1 inherit;padding:12px 22px;border:0;border-radius:10px;
background:#1d4ed8;color:#fff;cursor:pointer;margin:12px 0}
button:hover{background:#1a43bd}
table{border-collapse:collapse;width:100%;margin-top:14px;font-size:14px}
th,td{border-bottom:1px solid #d8d8e0;padding:8px 6px;text-align:left;vertical-align:top}
th{font-weight:600;opacity:.75}
td.n{width:64px;font:13px ui-monospace,monospace;opacity:.7}
.ok{padding:14px;border-radius:10px;background:#e8f5ec;color:#14532d;margin-top:14px}
@media(prefers-color-scheme:dark){.ok{background:#15321f;color:#bbf7d0}}
.next{margin-top:30px;padding:18px;border:1px solid #d8d8e0;border-radius:12px}
.next h2{font-size:1.05rem;margin:0 0 .5em}
.next ul{margin:.3em 0 1em 1.1em;padding:0}
</style>
<div class="wrap">
<h1>TLS Cert Lifetime Lint - SC-081v3 renewal check</h1>
<p class="sub">Finds the 12 settings that break when public TLS certificates fall to 100 days on 2027-03-15: openssl -days, Terraform, cert-manager, late expiry alerts, HPKP, TLS 1.0/1.1, SHA-1, RSA-1024.</p>
<textarea id="src" placeholder="Paste an openssl command, a Terraform file, a cert-manager Certificate or an nginx block">openssl req -x509 -newkey rsa:1024 -sha1 -days 365 -nodes -keyout edge.key -out edge.crt
resource "tls_self_signed_cert" "edge" {
validity_period_hours = 8760
}
spec:
duration: 8760h
- alert: CertExpiringSoon
expr: cert_expiry_days &lt; 14
# runbook: public TLS certificates are valid for 398 days, so we renew once a year.</textarea>
<button id="go">Check this config</button>
<div id="out"></div>
<div class="next"><h2>In the full version</h2><ul><li>The whole repository, not one open file</li><li>Take the findings away as CSV, JSON or HTML</li><li>CI JSON a pipeline can fail on</li><li><a href="https://getreadystack.com/api/buy/cl/polar_cl_SnmEdHDa8OjzORnIjOry1XW7LZozu9qDBYIIc1eBSB5">Get the full version - $29</a></li></ul></div>
</div>
<script>
var RULES=[{"id": "openssl-days-over-200", "pattern": "-days[\\s=]+(?:[1-9][0-9]{3,}|[3-9][0-9]{2}|2(?:[1-9][0-9]|0[1-9]))\\b", "flags": "", "sev": "error", "message": "openssl -days is over 200. Since 2026-03-15 a publicly trusted TLS certificate may not exceed 200 days (CA/Browser Forum ballot SC-081v3), and the cap falls to 100 days on 2027-03-15. A public CA will refuse or truncate this request.", "fix": "Use -days 90 and let ACME renew, or keep this key for an internal CA only."}, {"id": "openssl-days-101-200", "pattern": "-days[\\s=]+(?:1(?:[1-9][0-9]|0[1-9])|200)\\b", "flags": "", "sev": "warn", "message": "openssl -days is between 101 and 200. That is inside the 200-day cap in force today but over the 100-day cap that starts 2027-03-15 (SC-081v3). This request stops working on that date.", "fix": "Move to a 90-day ACME renewal before 2027-03-15."}, {"id": "tf-validity-hours-over-4800", "pattern": "validity_period_hours\\s*=\\s*(?:[1-9][0-9]{5,}|[1-9][0-9]{4}|[5-9][0-9]{3}|49[0-9]{2}|48[1-9][0-9]|480[1-9])\\b", "flags": "", "sev": "error", "message": "Terraform validity_period_hours is over 4800 hours (200 days), the public TLS maximum in force since 2026-03-15. On 2027-03-15 the ceiling becomes 2400 hours and on 2029-03-15 it becomes 1128 hours (47 days) - SC-081v3.", "fix": "Set validity_period_hours = 2160 (90 days) and drive renewal from ACME."}, {"id": "certmanager-duration-over-4800h", "pattern": "duration:\\s*\\\"?(?:[1-9][0-9]{5,}|[1-9][0-9]{4}|[5-9][0-9]{3}|49[0-9]{2}|48[1-9][0-9]|480[1-9])h\\b", "flags": "", "sev": "error", "message": "cert-manager duration is over 4800h (200 days). A publicly trusted issuer cannot honour it under SC-081v3; the certificate comes back shorter than the manifest claims, so renewBefore is computed against a lifetime that does not exist.", "fix": "duration: 2160h with renewBefore: 720h, and let the issuer own the schedule."}, {"id": "certmanager-duration-2401-4800h", "pattern": "duration:\\s*\\\"?(?:2(?:[5-9][0-9]{2}|4(?:[1-9][0-9]|0[1-9]))|3[0-9]{3}|4[0-7][0-9]{2}|4800)h\\b", "flags": "", "sev": "warn", "message": "cert-manager duration is between 2401h and 4800h. Legal today, refused from 2027-03-15 when the public TLS maximum drops to 100 days (2400h) - SC-081v3.", "fix": "Set duration: 2160h now so the 2027 change is a no-op."}, {"id": "expiry-alert-too-late", "pattern": "(?:cert(?:ificate)?[_-]?expiry|expiry[_-]?days|days[_-]?(?:until|to|before)[_-]?expir\\w*|expires?[_-]?in[_-]?days)\\D{0,12}\\b(?:[0-9]|1[0-9]|2[01])\\b", "flags": "i", "sev": "warn", "message": "This expiry alert only fires with 21 days or less left. Under a 100-day certificate (2027-03-15) and a 47-day certificate (2029-03-15) the renewal window has already closed by then, so the page arrives after the outage is unavoidable.", "fix": "Alert at one third of the certificate lifetime - 33 days for a 100-day certificate, 15 for a 47-day one."}, {"id": "hpkp-public-key-pins", "pattern": "Public-Key-Pins(?:-Report-Only)?\\b", "flags": "i", "sev": "error", "message": "HTTP Public Key Pinning is being sent. Every major browser removed support for it, and a pin set outlives a certificate that is now re-keyed every 47 to 100 days, so it locks visitors out of the site it was meant to protect.", "fix": "Delete the header; use a CAA record plus Certificate Transparency monitoring instead."}, {"id": "tls-1-0-1-1-enabled", "pattern": "(?:ssl_protocols|SSLProtocol|sslProtocols|ssl_min_version|minimum_protocol_version)\\b[^\\n]*\\bTLSv?1(?:[._]?[01])?(?![.\\d])", "flags": "", "sev": "error", "message": "TLS 1.0 or TLS 1.1 is still enabled. RFC 8996 deprecated both, current browsers refuse them, and PCI DSS forbids them for cardholder data.", "fix": "Leave only TLSv1.2 and TLSv1.3 on this directive."}, {"id": "go-mintls-10-11", "pattern": "tls\\.VersionTLS1[01]\\b", "flags": "", "sev": "error", "replace": "tls.VersionTLS12", "message": "Go tls.Config MinVersion is pinned to TLS 1.0 or 1.1, both deprecated by RFC 8996. Anything negotiating down to them is a downgrade path you are keeping open on purpose.", "fix": "MinVersion: tls.VersionTLS12"}, {"id": "sha1-signature", "pattern": "-sha1\\b", "flags": "", "sev": "error", "replace": "-sha256", "message": "SHA-1 signing is requested. Public CAs stopped signing SHA-1 certificates in 2016 and browsers reject the chain outright, so this certificate cannot be used on a public endpoint.", "fix": "-sha256"}, {"id": "rsa-key-under-2048", "pattern": "\\brsa:(?:512|1024)\\b", "flags": "", "sev": "error", "replace": "rsa:2048", "message": "An RSA key under 2048 bits is being generated. NIST SP 800-131A disallows it and no publicly trusted CA will sign it, so the request fails at issuance rather than at deployment.", "fix": "rsa:2048, or an EC P-256 key with -newkey ec -pkeyopt ec_paramgen_curve:P-256."}, {"id": "stale-max-lifetime-claim", "pattern": "\\b(?:397|398|825)\\b[^\\n]{0,24}\\bdays?\\b|\\bdays?\\b[^\\n]{0,24}\\b(?:397|398|825)\\b", "flags": "i", "sev": "warn", "message": "This text still states the old 397, 398 or 825-day maximum. The public TLS maximum has been 200 days since 2026-03-15, becomes 100 days on 2027-03-15 and 47 days on 2029-03-15 (SC-081v3), so anyone planning a renewal from this line plans it wrong.", "fix": "State the current cap and the two dated step-downs."}];
function scan(t){var L=String(t).split(/\r?\n/),h=[],i,r,re;
for(i=0;i<L.length;i++){for(var k=0;k<RULES.length;k++){r=RULES[k];
try{re=new RegExp(r.pattern,r.flags||'')}catch(e){continue}
if(re.test(L[i]))h.push({line:i+1,msg:r.message})}}
return h}
document.getElementById('go').onclick=function(){
var t=document.getElementById('src').value,o=document.getElementById('out');
if(!t.trim()){o.innerHTML='';return}
var h=scan(t);
if(!h.length){o.innerHTML='<div class="ok">Nothing in this file breaks under the SC-081v3 schedule</div>';return}
var s='<table><tr><th>Line</th><th>Finding</th></tr>';
for(var i=0;i<h.length;i++){s+='<tr><td class="n">'+h[i].line+'</td><td>'+
String(h[i].msg).replace(/&/g,'&amp;').replace(/</g,'&lt;')+'</td></tr>'}
o.innerHTML=s+'</table>'};
document.getElementById('go').click();
</script>
</html>
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.tls-cert-lifetime-lint" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'tls-cert-lifetime-lint',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/tls-cert-lifetime-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'tls-cert-lifetime-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/tls-cert-lifetime-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'tls-cert-lifetime-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://www.npmjs.com/package/@readystack/tls-cert-lifetime-lint" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'tls-cert-lifetime-lint',src:'mcp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">MCP server (npx)</a><a href="https://hub.docker.com/r/getreadystack/tls-cert-lifetime-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'tls-cert-lifetime-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.tls-cert-lifetime-lint
npx @readystack/tls-cert-lifetime-lint &lt;file&gt;
npx @readystack/tls-cert-lifetime-lint --mcp</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 12 rules TLS Cert Lifetime Lint - SC-081v3 renewal check checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"tls-cert-lifetime-lint",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Finds the 12 settings that break when public TLS certificates fall to 100 days on 2027-03-15: openssl -days, Terraform, cert-manager, late expiry alerts, HPKP, TLS 1.0/1.1, SHA-1, RSA-1024.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A certificate lifecycle management platform starts at $50,000-$100,000 a year plus $1-$5 per certificate (Keyfactor Command, 2026 vendor pricing).</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_SnmEdHDa8OjzORnIjOry1XW7LZozu9qDBYIIc1eBSB5" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>
<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-17">Updated 2026-09-17</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-17","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku30369_result_card.jpg" alt="TLS Cert Lifetime Lint - SC-081v3 renewal check" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>Six lines in this pipeline break TLS renewal, and they belong to the platform engineers running Terraform and cert-manager in production today.</p>
<p>This is what the extension prints for it, before a word of explanation:</p>
<pre><code>pipeline.txt
2: An RSA key under 2048 bits is being generated.
3: openssl -days is over 200.
6: Terraform validity_period_hours is over 4800 hours (200 days), the public TLS maximum in force since 2026-03-15.
9: cert-manager duration is over 4800h (200 days).
12: This expiry alert only fires with 21 days or less left.
15: HTTP Public Key Pinning is being sent.
-- 6 --</code></pre>
<p>Those six line numbers point at an ordinary renewal setup:</p>
<pre><code> 1 # renew.sh
2 openssl req -new -newkey rsa:1024 -nodes -keyout edge.key -out edge.csr
3 openssl x509 -req -days 365 -in edge.csr -signkey edge.key -out edge.crt
5 # edge.tf
6 validity_period_hours = 8760
8 # certificate.yaml
9 duration: 8760h
11 # alerts.yaml
12 expr: cert_expiry_days &lt; 14
14 # nginx.conf
15 add_header Public-Key-Pins &#x27;pin-sha256=&quot;...&quot;; max-age=5184000&#x27;;</code></pre>
<p>Nothing there looks wrong. It was all correct in 2024.</p>
<h3>What changed, and on which dates</h3>
<p>CA/Browser Forum ballot SC-081v3 passed in April 2025 and put the maximum lifetime of a publicly trusted TLS certificate on a fixed schedule. 200 days from 2026-03-15. 100 days from 2027-03-15. 47 days from 2029-03-15. Domain control validation reuse shrinks alongside it, down to 10 days by 2029.</p>
<p>The first step is behind us. The second, 2027-03-15, turns a six-monthly habit into an outage, because 100 days no longer fits inside any renewal cadence a human remembers to perform.</p>
<h3>Reading the six lines</h3>
<p>Lines 3, 6 and 9 all ask for a year, and a public CA will not issue a year. You get a refusal, or you get a shorter certificate than the manifest claims you have, which is worse: <code>renewBefore</code> is then computed against a lifetime that does not exist. Line 2 fails earlier still, at issuance rather than at deployment, because NIST SP 800-131A disallows RSA under 2048 bits.</p>
<p>Line 12 is the quiet one. Fourteen days of warning is generous against a 398-day certificate. Against a 100-day certificate, one third of the lifetime is 33 days, so that alert fires after the renewal window has already closed. Line 15 bites only at renewal: a pin set outlives a certificate re-keyed every 47 to 100 days, so the header locks visitors out of the site it was meant to protect.</p>
<h3>What the extension does</h3>
<p>TLS Cert Lifetime Lint carries the SC-081v3 schedule as 12 fixed rules rather than as recall. Alongside the six above it catches SHA-1 signing, which public CAs stopped doing in 2016, TLS 1.0 and 1.1, and the runbook line that still states the retired 398-day maximum. It reads openssl commands, Terraform, cert-manager YAML, nginx and Apache directives, Go <code>tls.Config</code> and Prometheus alert rules, and reports the line, the dated cap it breaks, and the value to use instead. What is already broken is separated from what breaks at the next milestone, so a backlog can be ordered rather than panicked over.</p>
<p>Checking a file you have open is free, and complete: every finding, every line number, nothing blurred and no trial counter. A licence adds the next job - the whole repository at once, the findings exported as CSV, JSON or HTML, and CI JSON so a pull request fails before an over-length certificate reaches production. An online SSL scanner tests a certificate that is already serving traffic, so it finds this after deployment; this reads the configuration before anything is issued.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku30369_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku30369_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does TLS Cert Lifetime Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads certificate configuration as text and flags settings that the CA/Browser Forum SC-081v3 schedule has already broken or will break on a named date. It checks openssl -days values, Terraform validity_period_hours, cert-manager duration, expiry alert thresholds, HPKP headers, TLS 1.0/1.1, SHA-1 signing and RSA keys under 2048 bits, and reports the line number, the cap that applies and the value to use instead.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Platform, SRE and DevOps engineers who issue publicly trusted TLS certificates from infrastructure as code - Terraform, cert-manager, Ansible, shell scripts around openssl - and who own the renewal that pages someone at 3am. It is aimed at teams that still have annual or six-monthly renewal habits written into repositories and runbooks.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask a chatbot or run an SSL scanner?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">An online SSL scanner tests a certificate that is already serving traffic, so it finds the problem after deployment. A chatbot answers from training data and still repeats the retired 398-day maximum. This reads the configuration in the repository before anything is issued, and carries the dated schedule - 200 days from 2026-03-15, 100 from 2027-03-15, 47 from 2029-03-15 - as fixed rules rather than recall.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free covers one file completely: open a config, run the check, and you see every one of the 12 findings with its line number, severity and replacement value. Nothing is blurred or limited by a trial counter. A licence adds the next job - scanning the whole repository, exporting the findings as CSV, JSON or HTML, and writing CI JSON so a pipeline fails before a bad certificate ships.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">How does the price compare to the alternative?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A certificate lifecycle management platform is the usual answer to this problem and it starts around $50,000 to $100,000 a year plus $1 to $5 per certificate at 2026 vendor pricing. This is $29 once,. It does not manage certificates - it stops the configuration mistakes that make a renewal fail in the first place.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. TLS Cert Lifetime Lint checks the file you open against 12 rules from a rule set dated 2026-09-20, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does TLS Cert Lifetime Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads certificate configuration as text and flags settings that the CA/Browser Forum SC-081v3 schedule has already broken or will break on a named date. It checks openssl -days values, Terraform validity_period_hours, cert-manager duration, expiry alert thresholds, HPKP headers, TLS 1.0/1.1, SHA-1 signing and RSA keys under 2048 bits, and reports the line number, the cap that applies and the value to use instead."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Platform, SRE and DevOps engineers who issue publicly trusted TLS certificates from infrastructure as code - Terraform, cert-manager, Ansible, shell scripts around openssl - and who own the renewal that pages someone at 3am. It is aimed at teams that still have annual or six-monthly renewal habits written into repositories and runbooks."}}, {"@type": "Question", "name": "Why not just ask a chatbot or run an SSL scanner?", "acceptedAnswer": {"@type": "Answer", "text": "An online SSL scanner tests a certificate that is already serving traffic, so it finds the problem after deployment. A chatbot answers from training data and still repeats the retired 398-day maximum. This reads the configuration in the repository before anything is issued, and carries the dated schedule - 200 days from 2026-03-15, 100 from 2027-03-15, 47 from 2029-03-15 - as fixed rules rather than recall."}}, {"@type": "Question", "name": "What is free and what needs a licence?", "acceptedAnswer": {"@type": "Answer", "text": "Free covers one file completely: open a config, run the check, and you see every one of the 12 findings with its line number, severity and replacement value. Nothing is blurred or limited by a trial counter. A licence adds the next job - scanning the whole repository, exporting the findings as CSV, JSON or HTML, and writing CI JSON so a pipeline fails before a bad certificate ships."}}, {"@type": "Question", "name": "How does the price compare to the alternative?", "acceptedAnswer": {"@type": "Answer", "text": "A certificate lifecycle management platform is the usual answer to this problem and it starts around $50,000 to $100,000 a year plus $1 to $5 per certificate at 2026 vendor pricing. This is $29 once,. It does not manage certificates - it stops the configuration mistakes that make a renewal fail in the first place."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. TLS Cert Lifetime Lint checks the file you open against 12 rules from a rule set dated 2026-09-20, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:30369,slug:"tls-cert-lifetime-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/autorenew-signup-lint"><span class="yj-rel-t">Auto-Renewal Signup Lint (California ARL)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cloud-cost-landmine-lint"><span class="yj-rel-t">Cloud Cost Landmine Lint for Terraform, CloudFormation and Kubernetes</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/eu-data-residency-lint"><span class="yj-rel-t">EU Data Residency Lint (Terraform, GDPR Ch. V)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/gitlab-ci-break-lint"><span class="yj-rel-t">GitLab CI Break Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ingress-nginx-retirement-lint"><span class="yj-rel-t">Ingress-NGINX Retirement Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pqc-deprecation-lint"><span class="yj-rel-t">PQC Deprecation Lint — RSA/ECC after 2030</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section>