Welcome to TiddlyWiki created by Jeremy Ruston; Copyright © 2004-2007 Jeremy Ruston, Copyright © 2007-2011 UnaMesa Association
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser
Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])
<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]
----
Also see [[AdvancedOptions]]
<!--{{{-->
<div class='header' role='banner'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}
h1, h2, h3, h4, h5, h6 { color: [[ColorPalette::SecondaryDark]]; }
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}
.txtOptionInput {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}
.header {
background: -moz-linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
background: linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
}
.header a:hover {background:transparent;}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}
.tabSelected {
color:[[ColorPalette::Foreground]];
background:[[ColorPalette::Background]];
border-left:1px solid [[ColorPalette::TertiaryLight]];
border-top:1px solid [[ColorPalette::TertiaryLight]];
border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}
#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}
.wizard { background:[[ColorPalette::PrimaryPale]]; }
.wizard__title { color:[[ColorPalette::PrimaryDark]]; border:none; }
.wizard__subtitle { color:[[ColorPalette::Foreground]]; border:none; }
.wizardStep { background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]]; }
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizardFooter .status a { color: [[ColorPalette::PrimaryPale]]; }
.wizard .button {
color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
border-color:[[ColorPalette::SecondaryDark]];
}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {
color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];
}
.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}
#messageArea { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]]; }
.messageToolbar__button { color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none; }
.messageToolbar__button_withIcon { background:inherit; }
.messageToolbar__button_withIcon:active { background:inherit; border:none; }
.tw-icon line { stroke: [[ColorPalette::TertiaryDark]]; }
.messageToolbar__button:hover .tw-icon line { stroke: [[ColorPalette::Foreground]]; }
.popup {
background: [[ColorPalette::Background]];
color: [[ColorPalette::TertiaryDark]];
box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]];
}
.popup li a, .popup li a:visited, .popup li a:hover, .popup li a:active {
color:[[ColorPalette::Foreground]]; border: none;
}
.popup li a:hover { background:[[ColorPalette::SecondaryLight]]; }
.popup li a:active { background:[[ColorPalette::SecondaryPale]]; }
.popup li.disabled { color:[[ColorPalette::TertiaryMid]]; }
.popupHighlight {color:[[ColorPalette::Foreground]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}
.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}
.tiddler .defaultCommand {font-weight:bold;}
.shadow .title {color:[[ColorPalette::TertiaryDark]];}
.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}
.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}
.tagging, .tagged { background: [[ColorPalette::Background]]; border: 2px solid [[ColorPalette::TertiaryPale]]; }
.selected .tagging, .selected .tagged { border: 2px solid [[ColorPalette::TertiaryLight]]; }
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button { border:none; }
.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}
.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}
.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}
.imageLink, #displayArea .imageLink {background:transparent;}
.annotation { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}
.twtable { background: [[ColorPalette::Background]]; }
.viewer th, .viewer thead td, .twtable th, .twtable thead td { background: [[ColorPalette::SecondaryMid]]; color: [[ColorPalette::Background]]; }
.viewer td, .viewer tr, .twtable td, .twtable tr { border: 1px solid [[ColorPalette::TertiaryLight]]; }
.twtable caption { color: [[ColorPalette::TertiaryMid]]; }
.viewer pre {background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}
.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}
.editor input {border:1px solid [[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}
#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
/*}}}*/
/*{{{*/
body { font-size:.75em; font-family:arial,helvetica,sans-serif; margin:0; padding:0; }
* html .tiddler {height:1%;}
h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}
hr {height:1px;}
dt {font-weight:bold;}
ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}
.txtOptionInput {width:11em; border-width: 1px; }
#contentWrapper .chkOptionInput {border:0;}
.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}
a {text-decoration:none;}
.externalLink {text-decoration:underline;}
.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}
/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}
#mainMenu .tiddlyLinkExisting,
#mainMenu .tiddlyLinkNonExisting,
#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}
.header {position:relative;}
.headerShadow {position:relative; padding:3em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:3em 0 1em 1em; left:0; top:0;}
.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}
#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}
#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}
#sidebarTabs li:not(:last-child) { margin-bottom: 0.3em; }
#sidebarTabs ul:not(:last-child) { margin-bottom: 0.5em; }
.wizard { padding:0.1em 2em 0; }
.wizard__title { font-size:2em; }
.wizard__subtitle { font-size:1.2em; }
.wizard__title, .wizard__subtitle { font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em; }
.wizardStep { padding:1em; }
.wizardFooter { padding: 0.8em 0; }
.wizardFooter .status { display: inline-block; line-height: 1.5; padding: 0.3em 1em; }
.wizardFooter .button { margin:0.5em 0 0; font-size:1.2em; padding:0.2em 0.5em; }
#messageArea { position:fixed; top:2em; right:0; margin:0.5em; padding:0.7em 1em; z-index:2000; }
.messageToolbar { text-align:right; padding:0.2em 0; }
.messageToolbar__button { text-decoration:underline; }
.messageToolbar__button_withIcon { display: inline-block; }
.tw-icon { height: 1em; width: 1em; } /* width for IE */
.tw-icon line { stroke-width: 1; stroke-linecap: round; }
.messageArea__text:not(:last-child) { margin-bottom: 0.3em; }
.messageArea__text a { text-decoration:underline; }
.popup {position:absolute; z-index:300; font-size:.9em; padding:0.3em 0; list-style:none; margin:0;}
.popup .popupMessage, .popup li.disabled, .popup li a { padding: 0.3em 0.7em; }
.popup li a {display:block; font-weight:normal; cursor:pointer;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}
.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}
.tabset {padding:1em 0 0 0.5em;}
.tab {display: inline-block; white-space: nowrap; position: relative; bottom: -0.7px; margin: 0 0.25em 0 0; padding:0.2em;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}
#contentWrapper {display:block;}
#splashScreen {display:none;}
#displayArea {margin:1em 17em 0 14em;}
.toolbar {text-align:right; font-size:.9em;}
.tiddler { padding: 1em; }
.title { font-size: 1.6em; font-weight: bold; }
.subtitle { font-size: 1.1em; }
.missing .viewer, .missing .title { font-style: italic; }
.missing .subtitle { display: none; }
.tiddler .button {padding:0.2em 0.4em;}
.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagged li, .tagging li { margin: 0.3em 0; }
.tagClear {clear:both;}
.footer {font-size:.9em;}
.footer li {display:inline;}
.annotation { padding: 0.5em 0.8em; margin: 0.5em 1px; }
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}
.viewer table, table.twtable { border-collapse: collapse; margin: 0.8em 0; }
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption { padding: 0.2em 0.4em; }
.twtable caption { font-size: 0.9em; }
table.listView { margin: 0.8em 1.0em; }
table.listView th, table.listView td, table.listView tr { text-align: left; }
.listView > thead { position: sticky; top: 0; }
* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer pre {padding:0.5em; overflow:auto;}
pre, code { font-family: monospace, monospace; font-size: 1em; }
.viewer pre, .viewer code { line-height: 1.4em; }
.editor {font-size:1.1em; line-height:1.4em;}
.editor input, .editor textarea { display: block; width: 100%; box-sizing: border-box; font: inherit; padding: 0.1em 0.4em; }
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0; padding-bottom:0;}
.fieldsetFix {border:0; padding:0; margin:1px 0;}
.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}
* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding: 0.3em 0.5em; display: inline-block;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel { display:none; z-index:100; position:absolute; width:90%; margin:0 5%; }
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}
.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea { display: none !important; }
#displayArea { margin: 1em 1em 0em; }
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
Ingress controllers can handle TLS encryption in three distinct modes. Termination is the most common: TLS is encrypted from the client to the ingress controller, then decrypted — traffic between the ingress and backend services flows as unencrypted HTTP. This simplifies backend services, which do not need to manage certificates, and centralizes TLS policy at the edge. Re-encryption applies TLS twice: the ingress decrypts the incoming HTTPS, then re-encrypts a separate TLS stream to the backend services, useful when backends require encrypted connections for compliance or when services are deployed in untrusted networks. Passthrough is least common: the ingress forwards raw TCP traffic without inspecting it, and the backend service handles TLS directly, preserving end-to-end encryption but sacrificing the ability to do layer-7 routing or inspection at the ingress layer. Choose termination for most deployments; use re-encryption or passthrough only when your backend architecture or security requirements demand it.
----
''Sources''
* <html><code>training/library/topics/api-gateways/primer.md</code></html>
''Related atoms''
* [[TLS termination point must match backend protocol expectations]]
* [[TLS termination location affects encryption, overhead, and secret management]]
cert-manager is a Kubernetes controller that automates TLS certificate management. It handles issuance (requesting certificates from Let's Encrypt, internal CAs, Vault, or self-signed), renewal (automatically re-issuing before expiry at 2/3 of the certificate's validity period), storage (writing certificates into Kubernetes Secrets), and Ingress integration (allowing you to annotate an Ingress resource and have cert-manager provision and renew its certificate automatically).
Without cert-manager, an operator must manually track renewal dates, run <html><code>certbot</code></html> or equivalent, copy PEM files into Secrets, and coordinate Ingress controller restarts. Manual management does not scale: three services fit in a spreadsheet; 30 services across four clusters do not. Missed renewals cause outages. Manual Secret handling leaks private keys into shell history and CI logs.
cert-manager was created by Jetstack (2017), acquired by Venafi (2020), and donated to the CNCF as a Sandbox project (2022). It is the de facto standard for Kubernetes certificate management and is installed in the majority of production clusters.
----
''Sources''
* <html><code>training/library/topics/api-gateways/primer.md</code></html>
* <html><code>training/library/topics/cert-manager/primer.md</code></html>
//Merged from 2 source atoms.//
''Related atoms''
* [[Certificates deployed without renewal automation cause surprise outages]]
When cert-manager uses self-signed or internal CA certificates, the CA is trusted by some services but not by others. The TLS handshake succeeds, but downstream pods that validate the full certificate chain fail because they lack the CA root in their trust store. This "trust distribution" problem — getting every pod in a cluster to trust an internal CA — is one of the most-reported support issues in the cert-manager project. Solutions include init containers that inject CA bundles, volume mounts, or (more cleanly) the trust-manager project, which was created specifically to solve this.
----
''Sources''
* <html><code>training/library/topics/cert-manager/trivia.md</code></html>
''Related atoms''
* [[cert-manager automates the full certificate lifecycle]]
A TLS certificate or API key deployed without automated renewal or expiry monitoring is a time bomb. The deadline is immovable — the CA sets it — and when it fires, it fires at 2 AM on a weekend. On expiry, connections fail immediately and the service is down until someone renews manually and redeploys. Teams often get away with the shortcut long enough that no one raises a flag, which is why the mistake persists.
The failure is invisible until it fires. Tests do not catch it because test suites run against long-lived test certificates. Monitoring does not catch it until the service is already down. Recovery is emergency firefighting — pages fire, war rooms fill, teams scramble to diagnose TLS failures — instead of a planned rotation.
Prevention requires two layers: automated renewal and expiry monitoring. Renewal tools include cert-manager in Kubernetes, Let's Encrypt with renewal scripts, and AWS Certificate Manager. Monitoring should alert at least 30 days before expiry (Prometheus alerts, calendar reminders) to catch cases where automation silently fails. Manual certificate management without either layer is a footgun guaranteed to fire eventually.
----
''Sources''
* <html><code>training/library/topics/compliance-automation/anti_primer.md</code></html>
* <html><code>training/library/topics/hashicorp-vault/anti_primer.md</code></html>
* <html><code>training/library/topics/falco/anti_primer.md</code></html>
* <html><code>training/library/topics/opsec-mistakes/anti_primer.md</code></html>
//Merged from 2 source atoms.//
''Related atoms''
* [[Certificate renewal must be fully automated]]
* [[cert-manager automates the full certificate lifecycle]]
The -k flag tells curl to skip TLS certificate verification. It exists for debugging self-signed certificates in development environments. When it leaks into production scripts, health checks, or CI pipelines, it disables the entire security guarantee of TLS — any attacker on the network can intercept the connection, forge a certificate, and capture credentials, tokens, or API keys. The excuse is always the same: "we had cert issues during the outage so we added -k and forgot to remove it." The real fix is to install the proper CA bundle, trust the internal CA, or update the system certificate store. Grep your codebase for curl.//-k and curl.//--insecure periodically and treat each match as a security incident.
----
''Sources''
* <html><code>training/library/topics/curl-and-wget/footguns.md</code></html>
''Related atoms''
* [[Missing TLS intermediate certificates break API clients and curl]]
* [[TLS certificate issues require openssl inspection and monitoring]]
etcd requires valid mutual TLS certificates for member-to-member communication. On kubeadm-managed clusters, these certificates expire after one year by default. Expired certificates are rejected immediately: members cannot communicate, the cluster partitions, and the API server loses connectivity to etcd, rendering the cluster unavailable or read-only. Failure manifests as cryptic TLS handshake errors in logs rather than an obvious expiry message.
Check expiry with <html><code>openssl x509 -in <cert> -noout -enddate</code></html> for each certificate under <html><code>/etc/kubernetes/pki/etcd/</code></html>, or with <html><code>kubeadm certs check-expiration</code></html> for a consolidated view. Renew all certificates with <html><code>kubeadm certs renew all</code></html>, then restart the kubelet with <html><code>systemctl restart kubelet</code></html>.
Prevention: automate expiration checks by running <html><code>kubeadm certs check-expiration</code></html> in a cron job or monitoring alert configured to trigger at least 30 days before expiry, converting a silent countdown into an actionable warning before it becomes an outage.
----
''Sources''
* <html><code>training/library/topics/etcd/footguns.md</code></html>
* <html><code>training/library/topics/etcd/street_ops.md</code></html>
//Merged from 2 source atoms.//
A TLS certificate chain consists of three parts: the leaf certificate (your domain), one or more intermediates (issued by the CA), and a root (self-signed, already in trust stores). Servers must send the leaf and all intermediates; the root is omitted because clients already have it in their trust stores. Web browsers cache intermediate certificates aggressively, so they often succeed even when the server omits them. API clients, curl, mobile clients, and automated systems do not cache intermediates and require the full chain to be present. When intermediates are missing, these strict clients fail with "Verify return code: 21 — unable to verify the first certificate." Chain order in the PEM file matters: server certificate first, intermediates next, root last or omitted. In nginx, build the bundle with <html><code>cat leaf.crt intermediate.crt > fullchain.crt</code></html> and point <html><code>ssl_certificate</code></html> at that file. This class of misconfiguration is routinely missed in development because browsers mask it, then surfaces in production when API integrations or automated health checks begin failing. Always validate with <html><code>curl -v</code></html> or <html><code>openssl s_client</code></html>, not a browser.
----
''Sources''
* <html><code>training/library/topics/http-protocol/footguns.md</code></html>
* <html><code>training/library/topics/http-protocol/street_ops.md</code></html>
//Merged from 2 source atoms.//
''Related atoms''
* [[-k/--insecure disables TLS verification and must never reach production]]
* [[TLS certificate issues require openssl inspection and monitoring]]
HTTPS runs HTTP over TLS, and the TLS handshake precedes any HTTP traffic. Common certificate issues: expiration (use <html><code>openssl x509 -enddate</code></html> to check), incomplete chains (missing intermediates), and hostname mismatch (SNI not matching certificate SANs). Use <html><code>openssl s_client -connect host:443 -servername host</code></html> to inspect the remote certificate, chain, and dates. Mixed content (HTTPS page loading HTTP resources) breaks in modern browsers. Automate certificate renewal (Let's Encrypt + cert-manager) and monitor at 30, 14, and 7 days before expiry.
----
''Sources''
* <html><code>training/library/topics/http-protocol/primer.md</code></html>
''Related atoms''
* [[Certificate renewal must be fully automated]]
* [[Certificates deployed without renewal automation cause surprise outages]]
* [[Cert-manager failures create hidden time bombs after expiry]]
Certificate expiration at 3 AM is a classic production incident. Certificates must be renewed automatically (Let's Encrypt with cert-manager or equivalent), never manually. Monitoring must alert at 30, 14, and 7 days before expiry to catch automation failures. DNS-based challenge (DNS-01) is more reliable than HTTP-based (HTTP-01).
----
''Sources''
* <html><code>training/library/topics/http-protocol/primer.md</code></html>
''Related atoms''
* [[Certificates deployed without renewal automation cause surprise outages]]
* [[TLS certificate issues require openssl inspection and monitoring]]
When a browser makes HTTPS through a corporate proxy, it first sends an HTTP CONNECT request asking the proxy to establish a raw TCP tunnel to the destination. The proxy responds "200 Connection Established" and blindly forwards bytes bidirectionally. The proxy cannot see encrypted traffic unless it performs TLS interception with its own certificate — exactly what corporate proxies do to enforce security policies, decrypting, inspecting, and re-encrypting each request without user visibility.
----
''Sources''
* <html><code>training/library/topics/http-protocol/trivia.md</code></html>
Let's Encrypt enforces a rate limit of five duplicate certificates per domain per week. When testing cert-manager with the production issuer, each iteration of your Certificate creation-and-deletion cycle consumes one certificate. After a few test runs, the limit is exhausted and all certificate issuance fails with HTTP 429 (Too Many Requests). If your domain is shared (e.g., a company domain), production TLS renewals are now blocked for days, affecting all services on that domain. Always use the Let's Encrypt staging issuer for development and troubleshooting: <html><code>https://acme-staging-v02.api.letsencrypt.org/directory</code></html>. The staging issuer issues fake certs (untrusted by browsers) but is functionally identical for testing and has no rate limits. Switch to production only after you've verified everything works in staging. Never use the production issuer in CI, dev clusters, or testing loops.
----
''Sources''
* <html><code>training/library/topics/k8s-ecosystem/footguns.md</code></html>
''Related atoms''
* [[TLS certificate issues require openssl inspection and monitoring]]
* [[Cert-manager failures create hidden time bombs after expiry]]
Ingress can terminate TLS at the edge (converting HTTPS to HTTP for the backend) or pass TLS through to the backend. If an Ingress is configured with <html><code>spec.tls[]</code></html> certificates and sends HTTP to a backend that expects HTTPS, the backend rejects the plaintext connection. The service appears down despite correct Ingress configuration: requests fail immediately rather than returning an error page. Conversely, if the Ingress tries to send HTTPS to a backend that expects HTTP, TLS handshake fails. The fix requires alignment: if you terminate TLS on the Ingress, the backend must accept HTTP. If the backend requires HTTPS, either pass TLS through or use a different Ingress plugin that can re-encrypt.
----
''Sources''
* <html><code>training/library/topics/k8s-services-and-ingress/anti_primer.md</code></html>
''Related atoms''
* [[TLS termination modes in Ingress controllers]]
Ingress without TLS serves traffic over plaintext HTTP, exposing credentials, tokens, and PII to anyone on the network path. This vulnerability is invisible until traffic is captured. Always configure TLS with a certificate, preferably using cert-manager to automate certificate lifecycle with Let's Encrypt, eliminating renewal overhead. Configure the Ingress to force HTTPS redirect so any plaintext connections are immediately upgraded. This single mitigation prevents a large class of data leakage incidents.
----
''Sources''
* <html><code>training/library/topics/k8s-services-and-ingress/footguns.md</code></html>
''Related atoms''
* [[TLS termination point must match backend protocol expectations]]
Ingress TLS can fail for several reasons. First, verify the TLS secret exists in the correct namespace (must be the same namespace as the Ingress) and is of type <html><code>kubernetes.io/tls</code></html> with <html><code>tls.crt</code></html> and <html><code>tls.key</code></html> keys. Decode and inspect the certificate — check that the Subject Alternative Names (SAN) include the hostname in the Ingress rule, and verify the certificate is not expired. If using cert-manager, check that Certificate and CertificateRequest resources exist and are not in error state. A common issue is an incomplete certificate chain — the <html><code>tls.crt</code></html> must include intermediate CA certificates, not just the leaf certificate. If the certificate is valid but TLS still doesn't work, verify the Ingress rule actually references the secret (via <html><code>spec.tls[].secretName</code></html>). HTTPS may fall back to HTTP if the secret is missing, appearing as connection allowed but insecure.
----
''Sources''
* <html><code>training/library/topics/k8s-services-and-ingress/street_ops.md</code></html>
''Related atoms''
* [[cert-manager automates the full certificate lifecycle]]
Using <html><code>ldap://</code></html> (unencrypted) without STARTTLS sends LDAP bind credentials in plaintext. Any network sniffer between the client and server captures the bind DN password. The right patterns are <html><code>ldaps://</code></html> (encrypted port 636) or <html><code>ldap://</code></html> with <html><code>ldap_id_use_start_tls = true</code></html> in sssd.conf. This matters because the bind password gives complete read/write access to the LDAP directory; in many setups it also matches or hints at domain admin credentials. Even on "trusted" networks, plaintext LDAP is a footgun — assume the network is sniffable and default to encrypted transport.
----
''Sources''
* <html><code>training/library/topics/ldap-identity/street_ops.md</code></html>
TLS termination at the load balancer (Client --[TLS]--> LB --[HTTP]--> Backend) is the most common pattern: the load balancer handles encryption/decryption, backends see plaintext HTTP. Simplicity and centralized certificate management are the benefits; the drawback is that backend-to-LB traffic is unencrypted, which may violate compliance requirements. TLS passthrough (Client --[TLS]--> LB (L4 mode) --[TLS]--> Backend) preserves end-to-end encryption but prevents Layer 7 inspection (the LB cannot read HTTP headers for routing). The LB operates at Layer 4, distributing raw TCP traffic. TLS re-encryption (Client --[TLS]--> LB --[TLS]--> Backend) provides Layer 7 routing with end-to-end encryption but doubles TLS overhead (the LB encrypts to backends and backends must decrypt). Each pattern has cost/security trade-offs. Load balancers must have access to TLS certificates — managing certificates across clusters requires careful tooling to rotate and distribute them securely.
----
''Sources''
* <html><code>training/library/topics/load-balancing/primer.md</code></html>
''Related atoms''
* [[TLS termination modes in Ingress controllers]]
openssl s_client connects to a TLS service and displays the certificate chain, negotiated protocol, cipher selection, and expiration dates without requiring a browser. SNI support allows testing certificates on shared hosts with multiple certificates per IP. Certificate expiration, chain gaps, self-signed status, and cipher weakness are immediately visible. STARTTLS variants support testing mail (SMTP, IMAP, POP3), LDAP, and other protocols that layer TLS over plain TCP. It is essential for debugging certificate mismatches and protocol negotiation problems.
----
''Sources''
* <html><code>training/library/topics/networking-troubleshooting/tools-reference.md</code></html>
''Related atoms''
* [[TLS certificate issues require openssl inspection and monitoring]]
TLS termination in nginx requires <html><code>ssl_certificate</code></html> and <html><code>ssl_certificate_key</code></html> paths, then protocol and cipher configuration. Use <html><code>ssl_protocols TLSv1.2 TLSv1.3;</code></html> (disable TLS 1.0 and 1.1). Modern ciphers like <html><code>ECDHE-ECDSA-AES128-GCM-SHA256</code></html> support forward secrecy. Enable <html><code>ssl_stapling</code></html> to include the OCSP response in the handshake, avoiding client OCSP requests and latency. Use <html><code>ssl_session_cache shared:SSL:10m;</code></html> to cache session tokens across workers, reducing handshake overhead on reconnect. Set <html><code>ssl_session_tickets off;</code></html> if you manage your own session resumption. Add <html><code>Strict-Transport-Security: max-age=63072000;</code></html> response header to tell browsers to use HTTPS only for this domain for two years, preventing MITM downgrades. Create a separate HTTP <html><code>server {}</code></html> block that redirects to HTTPS: <html><code>listen 80; return 301 https://$host$request_uri;</code></html>
----
''Sources''
* <html><code>training/library/topics/nginx-web-servers/primer.md</code></html>
''Related atoms''
* [[Missing TLS intermediate certificates break API clients and curl]]
* [[TLS certificate issues require openssl inspection and monitoring]]
* [[TLS termination location affects encryption, overhead, and secret management]]
When cert-manager stops running, existing TLS certificates continue to work until their expiration date — typically 60–90 days for Let's Encrypt. This creates a false sense of safety during the incident: services appear fine, so teams don't treat the outage as critical. The real outage arrives months later when certificates expire in a cascade, causing widespread failures. To catch this early, monitor <html><code>certmanager_certificate_expiration_timestamp_seconds</code></html> in Prometheus and alert when any certificate has fewer than 14 days remaining. With proper monitoring, you'll know within 24 hours of a cert-manager outage that trouble is coming.
----
''Sources''
* <html><code>training/library/topics/platform-engineering/street_ops.md</code></html>
''Related atoms''
* [[Certificates deployed without renewal automation cause surprise outages]]
* [[TLS certificate issues require openssl inspection and monitoring]]
!! MOC — footguns
Every atom extracted from a ''footgun'' source (1 total).
* [[Certificates deployed without renewal automation cause surprise outages]]
!! MOC — other
Every atom extracted from a ''other'' source (18 total).
* [[-k/--insecure disables TLS verification and must never reach production]]
* [[Always configure TLS on Ingress to protect data in transit]]
* [[Cert-manager failures create hidden time bombs after expiry]]
* [[Certificate renewal must be fully automated]]
* [[HTTP CONNECT tunnels encrypted traffic through proxies]]
* [[Ingress TLS failures require secret, certificate, and controller verification]]
* [[LDAP credentials exposed on unencrypted connections]]
* [[Missing TLS intermediate certificates break API clients and curl]]
* [[Self-signed CAs create trust distribution problems]]
* [[TLS certificate issues require openssl inspection and monitoring]]
* [[TLS termination location affects encryption, overhead, and secret management]]
* [[TLS termination modes in Ingress controllers]]
* [[TLS termination point must match backend protocol expectations]]
* [[TLS termination: modern ciphers, OCSP stapling, session caching, HSTS]]
* [[Testing cert-manager against production Let's Encrypt exhausts rate limits]]
* [[cert-manager automates the full certificate lifecycle]]
* [[etcd TLS certificate expiration causes cluster partition]]
* [[openssl s_client inspects TLS certificates and negotiation]]
!! MOC — confidence high
Atoms with confidence in the ''high'' band (17 total).
* [[-k/--insecure disables TLS verification and must never reach production]]
* [[Always configure TLS on Ingress to protect data in transit]]
* [[Certificate renewal must be fully automated]]
* [[Certificates deployed without renewal automation cause surprise outages]]
* [[HTTP CONNECT tunnels encrypted traffic through proxies]]
* [[Ingress TLS failures require secret, certificate, and controller verification]]
* [[LDAP credentials exposed on unencrypted connections]]
* [[Missing TLS intermediate certificates break API clients and curl]]
* [[Self-signed CAs create trust distribution problems]]
* [[TLS certificate issues require openssl inspection and monitoring]]
* [[TLS termination location affects encryption, overhead, and secret management]]
* [[TLS termination modes in Ingress controllers]]
* [[TLS termination: modern ciphers, OCSP stapling, session caching, HSTS]]
* [[Testing cert-manager against production Let's Encrypt exhausts rate limits]]
* [[cert-manager automates the full certificate lifecycle]]
* [[etcd TLS certificate expiration causes cluster partition]]
* [[openssl s_client inspects TLS certificates and negotiation]]
!! MOC — confidence mid
Atoms with confidence in the ''mid'' band (2 total).
* [[Cert-manager failures create hidden time bombs after expiry]]
* [[TLS termination point must match backend protocol expectations]]
!! MOC — merged atoms
Atoms that were consolidated from 2+ source concepts during cross-dedup (4 total). Reading these is a cheap way to see where the pipeline found duplication worth collapsing.
* [[Certificates deployed without renewal automation cause surprise outages]]
* [[Missing TLS intermediate certificates break API clients and curl]]
* [[cert-manager automates the full certificate lifecycle]]
* [[etcd TLS certificate expiration causes cluster partition]]
!! Maps of Content
! By kind
* [[MOC: footguns]]
* [[MOC: other]]
! By confidence
* [[MOC: confidence high]]
* [[MOC: confidence mid]]
! Quality
* [[MOC: merged atoms]]
TLS & certificates — atoms deck
canonical atomic concepts from tls-certificates-ops
GettingStarted
[[MOC: index]]
[[GettingStarted]]
[[MOC: index]]
----
''By kind''
* [[MOC: footguns]]
* [[MOC: trivia]]
* [[MOC: flashcards]]
* [[MOC: compendium q&a]]
* [[MOC: primer]]
* [[MOC: anti-primer]]
* [[MOC: street ops]]
* [[MOC: cheatsheet]]
----
''By confidence''
* [[MOC: confidence high]]
* [[MOC: confidence mid]]
----
''Quality''
* [[MOC: merged atoms]]
!! TLS & certificates — atoms deck
''19 atoms'' — canonical atomic concepts from tls-certificates-ops
//Each tiddler is one atomic concept. Sources and related atoms are listed in the footer. Cross-dedup has already merged duplicates, so every concept should appear exactly once.//
! Start here
* [[MOC: index]] — master index of MOCs
* [[MOC: merged atoms]] — concepts consolidated from multiple sources
! Breakdown — by kind
|!Kind|!Count|!Jump|h
|Other|18|[[MOC: other]]|
|Footguns|1|[[MOC: footguns]]|
! Breakdown — by confidence
|!Band|!Count|!Jump|h
|high|17|[[MOC: confidence high]]|
|mid|2|[[MOC: confidence mid]]|
! Pipeline provenance
* Raw extracted atoms (whole corpus): 17641
* After intra-source dedup (whole corpus): 7753
* In this deck (domain = tls, post cross-dedup): 19
* Atoms in this deck merged from multiple sources: 4
See ''FULL-CORPUS-REPORT.md'' in the grokzett repo for full metrics.
/* grokzett TWC deck theme overrides */
body, #contentWrapper { font-family: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; }
.tiddler { margin-bottom: 1.5em; }
.tiddler .title { font-size: 1.4em; letter-spacing: -0.01em; }
.viewer { line-height: 1.55; }
.viewer h1, .viewer h2, .viewer h3 { border-bottom: none; margin-top: 1.2em; }
.viewer h1 { font-size: 1.35em; }
.viewer h2 { font-size: 1.20em; }
.viewer h3 { font-size: 1.05em; color: #444; }
.viewer blockquote { border-left: 3px solid #c9d6df; margin: 1em 0; padding: 0.2em 1em; background: #f6f9fb; color: #333; }
.viewer code { background: #f2f2f2; padding: 1px 5px; border-radius: 3px; font-size: 0.92em; }
.viewer pre { background: #282c34; color: #abb2bf; padding: 0.8em 1em; border-radius: 6px; overflow-x: auto; font-size: 0.88em; line-height: 1.4; }
.viewer pre code { background: transparent; padding: 0; color: inherit; border-radius: 0; }
.viewer pre.literal { background: #282c34; color: #abb2bf; }
.viewer table { border-collapse: collapse; margin: 1em 0; font-size: 0.92em; width: auto; }
.viewer th, .viewer td { border: 1px solid #d8dee4; padding: 6px 10px; }
.viewer th { background: #eef2f6; text-align: left; }
.viewer tr:nth-child(even) td { background: #fbfcfd; }
.viewer hr { border: none; border-top: 1px solid #dde3e9; margin: 1.5em 0; }
.tagged { background: #eef5fb; padding: 4px 8px; border-radius: 4px; margin-right: 4px; }
/* grokzett status controls (injected by features.js per tiddler) */
.grokzett-status {
font-size: 0.85em; margin: 0.3em 0 1em; color: #555;
display: flex; align-items: center; gap: 6px;
}
.grokzett-status .gz-label { color: #888; letter-spacing: 0.02em; }
.grokzett-status button {
border: 1px solid #c9d6df; background: #f7f9fb; padding: 2px 10px;
font-size: 0.92em; cursor: pointer; border-radius: 12px; color: #333;
}
.grokzett-status button:hover { background: #e6edf3; }
.grokzett-status button.active { background: #2b6cb0; color: white; border-color: #2b6cb0; }
/* Fixed filter bar (top-right) */
.grokzett-filter-bar {
position: fixed; top: 10px; right: 10px; z-index: 10000;
background: #2d3748; color: #e2e8f0;
padding: 8px 14px; border-radius: 8px;
font-size: 0.85em; font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
display: flex; align-items: center; gap: 12px;
box-shadow: 0 3px 12px rgba(0,0,0,0.25);
}
.grokzett-filter-bar .gz-title { font-weight: 600; letter-spacing: 0.02em; }
.grokzett-filter-bar select, .grokzett-filter-bar button {
background: #4a5568; color: #e2e8f0; border: 1px solid #718096;
border-radius: 4px; padding: 2px 8px; font: inherit;
}
.grokzett-filter-bar button { cursor: pointer; }
.grokzett-filter-bar button:hover { background: #5a6678; }
.grokzett-filter-bar label { display: flex; align-items: center; gap: 4px; }
.grokzett-filter-bar #gz-counts { opacity: 0.75; font-size: 0.95em; }
/* Subtle status badge on each tiddler (color bar at left) */
.tiddler[data-gz-status="learning"] { border-left: 3px solid #ed8936; padding-left: 8px; }
.tiddler[data-gz-status="known"] { border-left: 3px solid #48bb78; padding-left: 8px; opacity: 0.7; }
/* Cloze spans — trivia mode */
.gz-cloze {
background: #f6e05e; color: #f6e05e; border-radius: 3px; padding: 0 4px;
cursor: pointer; user-select: none; transition: color 0.15s;
}
.gz-cloze.revealed { color: #533f03; background: #fef6ad; }
/* Flashcard Q/A layout */
.gz-flash-a {
margin-top: 1em; padding: 0.8em 1em; background: #f7fafc;
border-radius: 6px; border: 1px solid #e2e8f0; position: relative;
}
.gz-flash-a.hidden > * { filter: blur(5px); user-select: none; }
.gz-flash-a.hidden { cursor: pointer; }
.gz-flash-a.hidden::after {
content: "click to reveal answer";
position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%);
text-align: center; color: #718096; font-size: 0.9em; letter-spacing: 0.05em;
pointer-events: none;
}
.gz-flash-a:not(.hidden) { border-left: 4px solid #48bb78; }