Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9dbee18a42 | ||
|
|
905392947d | ||
|
|
faf55dc1be | ||
|
|
0d84921a56 | ||
|
|
716e62524a | ||
|
|
74c9b3cea7 | ||
|
|
f3f3a8da46 |
@@ -104,3 +104,95 @@
|
||||
[ 1134809ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1136553ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1141191ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1158221ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1173507ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1190834ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1198506ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1217761ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1231342ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1233528ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1243017ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1253381ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1256056ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1258513ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1271317ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1284530ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1301830ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1307562ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1310330ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1317970ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1328668ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1336338ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1340155ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1346989ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1348836ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1352113ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1367871ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1371158ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1390720ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1405259ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1420920ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1433518ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1450513ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1453685ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1460654ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1470589ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1489330ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1503666ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1521587ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1537970ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1540426ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1548105ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1549441ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1567671ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1585493ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1597054ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1602669ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1607866ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1623290ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1631460ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1640086ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1645979ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1650742ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1652863ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1663908ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1666587ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1668427ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1676825ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1687882ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1691062ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1698532ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1709597ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1725669ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1739294ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1744412ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1753319ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1761792ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1765298ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1784381ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1786396ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1798982ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1807180ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1823569ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1837292ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1838720ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1848387ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1856847ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1866742ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1879249ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1884700ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1900774ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1912256ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1931088ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1937844ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1948191ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1951360ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1957512ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1958836ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1979011ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 1993551ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 2011369ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 2024782ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 2040763ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 2044650ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
[ 2061337ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 302 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
[ 12202ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://app2.hyeonworks.com/favicon.ico:0
|
||||
@@ -0,0 +1 @@
|
||||
[ 451ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://app2.hyeonworks.com/favicon.ico:0
|
||||
@@ -0,0 +1,16 @@
|
||||
- generic [ref=f68e3]:
|
||||
- banner [ref=f68e4]:
|
||||
- generic [ref=f68e5]: keycloak-patterns
|
||||
- main [ref=f68e6]:
|
||||
- heading "Sign in to your account" [level=1] [ref=f68e8]
|
||||
- generic [ref=f68e12]:
|
||||
- generic [ref=f68e13]:
|
||||
- generic [ref=f68e14]: Username or email
|
||||
- textbox "Username or email" [ref=f68e17]
|
||||
- generic [ref=f68e18]:
|
||||
- generic [ref=f68e19]: Password
|
||||
- generic [ref=f68e21]:
|
||||
- textbox "Password" [ref=f68e24]
|
||||
- button "Show password" [ref=f68e26] [cursor=pointer]:
|
||||
- generic [aria-hidden] [ref=f68e27]:
|
||||
- button "Sign In" [ref=f68e30] [cursor=pointer]
|
||||
@@ -0,0 +1 @@
|
||||
- generic [active] [ref=f69e1]: "{ \"headers\" : { \"host\" : [ \"app2.hyeonworks.com\" ], \"user-agent\" : [ \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36\" ], \"accept\" : [ \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\" ], \"accept-encoding\" : [ \"gzip, deflate, br, zstd\" ], \"accept-language\" : [ \"en-US,en;q=0.9\" ], \"cache-control\" : [ \"max-age=0\" ], \"cookie\" : [ \"grafana_session=bfb5f2c2406b3f163ea01063ac1b8b83; grafana_session_expiry=1788508427; _oauth2_proxy=djIuWDI5aGRYUm9NbDl3Y205NGVTMHhNamhoWXprNFpHSmxORGRoT0RObU16UmlNemMxTTJJd016ZGlZakpqTWcuQVVUYldxYkFlejYxNXozUUZBcGh1dw==|1788508274|biz4o9E4vZXX07LnF32LU7tIEMrvfwxwCIBsZkxpwbY=\" ], \"priority\" : [ \"u=0, i\" ], \"sec-ch-ua\" : [ \"\\\"Chromium\\\";v=\\\"152\\\", \\\"Not?A_Brand\\\";v=\\\"24\\\", \\\"Google Chrome\\\";v=\\\"152\\\"\" ], \"sec-ch-ua-mobile\" : [ \"?0\" ], \"sec-ch-ua-platform\" : [ \"\\\"Linux\\\"\" ], \"sec-fetch-dest\" : [ \"document\" ], \"sec-fetch-mode\" : [ \"navigate\" ], \"sec-fetch-site\" : [ \"same-site\" ], \"sec-fetch-user\" : [ \"?1\" ], \"upgrade-insecure-requests\" : [ \"1\" ], \"x-forwarded-email\" : [ \"labuser@example.com\" ], \"x-forwarded-host\" : [ \"app2.hyeonworks.com\" ], \"x-forwarded-port\" : [ \"443\" ], \"x-forwarded-preferred-username\" : [ \"labuser\" ], \"x-forwarded-proto\" : [ \"https\" ], \"x-forwarded-server\" : [ \"traefik-5d6fcf895-wpfhr\" ], \"x-forwarded-user\" : [ \"27df5ea9-8703-4ec5-badd-d972c583e1ff\" ], \"x-real-ip\" : [ \"100.123.124.30\" ] }, \"remoteAddr\" : \"100.123.124.30\", \"localAddr\" : \"10.42.1.132\", \"scheme\" : \"https\", \"secure\" : true, \"serverName\" : \"app2.hyeonworks.com\", \"serverPort\" : 443, \"requestUrl\" : \"https://app2.hyeonworks.com/api/echo\" }"
|
||||
@@ -0,0 +1 @@
|
||||
- generic [ref=f70e1]: "{ \"headers\" : { \"host\" : [ \"app2.hyeonworks.com\" ], \"user-agent\" : [ \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36\" ], \"accept\" : [ \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\" ], \"accept-encoding\" : [ \"gzip, deflate, br, zstd\" ], \"accept-language\" : [ \"en-US,en;q=0.9\" ], \"cookie\" : [ \"grafana_session=bfb5f2c2406b3f163ea01063ac1b8b83; grafana_session_expiry=1788508427; _oauth2_proxy=djIuWDI5aGRYUm9NbDl3Y205NGVTMWhOakZqTlRjM1ptSTVORFF5TVdWbU1qQmpaak5pWXpka1pXRTFPR1F6WWcuOXF3TmRyQzJIOFlrSDh6T1pTMl91QQ==|1788508374|Ehcd4hjNk0noEy2MSPI-C5jg84JZmilWcKhuj8OH3uw=\" ], \"priority\" : [ \"u=0, i\" ], \"sec-ch-ua\" : [ \"\\\"Chromium\\\";v=\\\"152\\\", \\\"Not?A_Brand\\\";v=\\\"24\\\", \\\"Google Chrome\\\";v=\\\"152\\\"\" ], \"sec-ch-ua-mobile\" : [ \"?0\" ], \"sec-ch-ua-platform\" : [ \"\\\"Linux\\\"\" ], \"sec-fetch-dest\" : [ \"document\" ], \"sec-fetch-mode\" : [ \"navigate\" ], \"sec-fetch-site\" : [ \"none\" ], \"sec-fetch-user\" : [ \"?1\" ], \"upgrade-insecure-requests\" : [ \"1\" ], \"x-forwarded-email\" : [ \"changed-labuser@example.com\" ], \"x-forwarded-host\" : [ \"app2.hyeonworks.com\" ], \"x-forwarded-port\" : [ \"443\" ], \"x-forwarded-preferred-username\" : [ \"labuser\" ], \"x-forwarded-proto\" : [ \"https\" ], \"x-forwarded-server\" : [ \"traefik-5d6fcf895-wpfhr\" ], \"x-forwarded-user\" : [ \"27df5ea9-8703-4ec5-badd-d972c583e1ff\" ], \"x-real-ip\" : [ \"100.123.124.30\" ] }, \"remoteAddr\" : \"100.123.124.30\", \"localAddr\" : \"10.42.0.53\", \"scheme\" : \"https\", \"secure\" : true, \"serverName\" : \"app2.hyeonworks.com\", \"serverPort\" : 443, \"requestUrl\" : \"https://app2.hyeonworks.com/api/echo\" }"
|
||||
@@ -0,0 +1,94 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 520" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif">
|
||||
<style>
|
||||
.box{fill:#fff;stroke:#8c959f;stroke-width:1.4;rx:6}
|
||||
.dead{fill:#fff5f5;stroke:#cf222e;stroke-width:1.6;stroke-dasharray:5 3;rx:6}
|
||||
.ok{fill:#f6fdf6;stroke:#1a7f37;stroke-width:1.6;rx:6}
|
||||
.t{font-size:12px;fill:#1f2328}
|
||||
.tb{font-size:12.5px;fill:#1f2328;font-weight:600}
|
||||
.s{font-size:10.5px;fill:#656d76}
|
||||
.ttl{font-size:14px;fill:#1f2328;font-weight:600}
|
||||
.r{stroke:#cf222e;stroke-width:1.6;fill:none}
|
||||
.g{stroke:#1a7f37;stroke-width:1.6;fill:none}
|
||||
.k{stroke:#8c959f;stroke-width:1.3;fill:none}
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#8c959f"/></marker>
|
||||
<marker id="ar" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#cf222e"/></marker>
|
||||
<marker id="ag" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#1a7f37"/></marker>
|
||||
</defs>
|
||||
|
||||
<text x="20" y="26" class="ttl">D-4 — 「갱신 성공」과 「새 인증서 서빙」 사이의 36분 39초</text>
|
||||
<text x="20" y="44" class="s">측정: 2026-09-04 · 일련번호 5초 간격 564표본 · 새 연결 0.2초 간격 8856건</text>
|
||||
|
||||
<!-- 좌: 디스크 -->
|
||||
<rect x="20" y="70" width="250" height="196" class="box"/>
|
||||
<text x="34" y="92" class="tb">디스크 — certbot</text>
|
||||
<rect x="36" y="104" width="218" height="46" class="box"/>
|
||||
<text x="48" y="122" class="t">cert1.pem</text>
|
||||
<text x="48" y="138" class="s">09-03 10:47:40 · notAfter Dec 2</text>
|
||||
<rect x="36" y="158" width="218" height="46" class="ok"/>
|
||||
<text x="48" y="176" class="t">cert2.pem</text>
|
||||
<text x="48" y="192" class="s">09-04 17:22:13 · notAfter Dec 3</text>
|
||||
<text x="36" y="224" class="s">certbot renew --force-renewal</text>
|
||||
<text x="36" y="240" class="s">→ 성공. live/ 링크가 2번을 가리킨다</text>
|
||||
<text x="36" y="256" class="s">경로는 그대로, 내용만 바뀐다</text>
|
||||
|
||||
<!-- 중: 끊긴 고리 -->
|
||||
<rect x="300" y="96" width="260" height="144" class="dead"/>
|
||||
<text x="316" y="118" class="tb">★ 잇는 것이 없다</text>
|
||||
<text x="316" y="140" class="t">1. ExecStartPost</text>
|
||||
<text x="470" y="140" class="t" fill="#cf222e">없음</text>
|
||||
<text x="316" y="160" class="t">2. renewal-hooks/deploy/</text>
|
||||
<text x="470" y="160" class="t" fill="#cf222e">비었음</text>
|
||||
<text x="316" y="180" class="t">3. certbot nginx 플러그인</text>
|
||||
<text x="470" y="180" class="t" fill="#cf222e">없음</text>
|
||||
<text x="316" y="206" class="s">post/ · pre/ 도 비어 있다 (total 8)</text>
|
||||
<text x="316" y="222" class="s">셋 다 비면 아무도 reload 를 부르지 않는다</text>
|
||||
<path d="M270 168 L296 168" class="r" marker-end="url(#ar)"/>
|
||||
<path d="M300 230 L560 108" stroke="#cf222e" stroke-width="1.2" stroke-dasharray="4 3"/>
|
||||
<path d="M300 108 L560 230" stroke="#cf222e" stroke-width="1.2" stroke-dasharray="4 3"/>
|
||||
|
||||
<!-- 우: nginx -->
|
||||
<rect x="590" y="70" width="250" height="196" class="box"/>
|
||||
<text x="604" y="92" class="tb">nginx — 메모리</text>
|
||||
<rect x="606" y="104" width="218" height="60" class="dead"/>
|
||||
<text x="618" y="124" class="t">기동 시 읽은 cert1</text>
|
||||
<text x="618" y="140" class="s">master 585 / worker 586</text>
|
||||
<text x="618" y="156" class="s">둘 다 09-03 19:00:39, 22.4시간째</text>
|
||||
<text x="606" y="184" class="s">reload 없이는 디스크를 다시 안 본다.</text>
|
||||
<text x="606" y="200" class="s">reload 하면 마스터는 남고</text>
|
||||
<text x="606" y="216" class="s">워커만 새로 뜬다 → 워커 PID 로 확인</text>
|
||||
<text x="606" y="240" class="s">ssl_certificate .../fullchain.pem</text>
|
||||
<path d="M564 168 L586 168" class="k" marker-end="url(#a)"/>
|
||||
|
||||
<!-- 타임라인 -->
|
||||
<text x="20" y="306" class="tb">밖에서 본 것 — 일련번호 (5초 간격)</text>
|
||||
<line x1="60" y1="356" x2="800" y2="356" class="k"/>
|
||||
<line x1="60" y1="350" x2="60" y2="362" class="k"/>
|
||||
<line x1="300" y1="350" x2="300" y2="362" class="k"/>
|
||||
<line x1="660" y1="344" x2="660" y2="368" stroke="#1a7f37" stroke-width="2"/>
|
||||
<line x1="800" y1="350" x2="800" y2="362" class="k"/>
|
||||
<text x="46" y="382" class="s">08:10:51</text>
|
||||
<text x="278" y="382" class="s">08:22:13</text>
|
||||
<text x="620" y="382" class="s">08:58:52</text>
|
||||
<text x="770" y="382" class="s">09:02</text>
|
||||
<text x="278" y="398" class="s">디스크 기록</text>
|
||||
<text x="618" y="398" class="s">nginx -s reload</text>
|
||||
|
||||
<rect x="60" y="330" width="600" height="16" class="dead"/>
|
||||
<text x="300" y="342" class="s" text-anchor="middle" fill="#cf222e">0520BB…B853 (옛 인증서) — 이 구간에서 428회 관측</text>
|
||||
<rect x="660" y="330" width="140" height="16" class="ok"/>
|
||||
<text x="730" y="342" class="s" text-anchor="middle" fill="#1a7f37">06C7CB…EA1D</text>
|
||||
<path d="M300 416 L660 416" class="r" marker-end="url(#ar)"/>
|
||||
<path d="M660 416 L300 416" class="r" marker-end="url(#ar)"/>
|
||||
<text x="480" y="410" class="tb" text-anchor="middle" fill="#cf222e">36분 39초</text>
|
||||
<text x="480" y="434" class="s" text-anchor="middle">사람이 reload 했기에 36분이다. 아무도 안 했다면 다음 재시작까지 — 무기한</text>
|
||||
|
||||
<!-- reload 판정 -->
|
||||
<rect x="20" y="452" width="400" height="52" class="ok"/>
|
||||
<text x="34" y="472" class="tb">reload 는 무중단이었다</text>
|
||||
<text x="34" y="490" class="s">새 연결 8856건 전부 200 · p95 205.7 → 204.3ms (변화 없음)</text>
|
||||
<rect x="440" y="452" width="400" height="52" class="ok"/>
|
||||
<text x="454" y="472" class="tb">진행 중이던 요청도 살아남았다</text>
|
||||
<text x="454" y="490" class="s">전송 12초째에 reload · 845361바이트 전량 · 연결수 1</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,19 @@
|
||||
D-4 대조군 — 주입 없는 상태의 가용성 잡음 바닥
|
||||
수집 시각(dev): 2026-09-04T08:03:07Z UTC
|
||||
대상: https://auth.hyeonworks.com/realms/master · 0.2초 간격 900회 = 180초
|
||||
형식: http_code time_total time_appconnect(TLS 핸드셰이크까지)
|
||||
왜: 갱신 중 000 이 한 번 나와도, 평시 오류율을 모르면 그게 갱신 탓인지 알 수 없다.
|
||||
----------------------------------------------------------------
|
||||
표본 900 개
|
||||
|
||||
[상태코드 분포]
|
||||
900 200
|
||||
|
||||
[응답시간 ms]
|
||||
최소 67 중앙 98 p95 195 최대 1121 평균 106.9
|
||||
|
||||
[TLS 핸드셰이크 ms — 0 이면 연결 재사용, >0 이면 새 핸드셰이크]
|
||||
핸드셰이크 발생 900회 / 900 평균 83 ms 최대 1100 ms
|
||||
|
||||
[비정상 응답 원문 — 있으면 아래에 전부]
|
||||
비200 총 0
|
||||
@@ -0,0 +1,22 @@
|
||||
D-4 대조군 2 — '진행 중이던 요청' 측정 장치의 무주입 동작
|
||||
수집 시각(dev): 2026-09-04T08:08:45Z UTC
|
||||
|
||||
왜 이 장치가 따로 필요한가
|
||||
05-control 의 0.2초 폴링은 매 요청이 새 TCP 연결이다(핸드셰이크 900/900).
|
||||
그래서 '새 연결을 받아주는가'는 재지만, D-4 가 묻는 '이미 진행 중이던
|
||||
요청이 어떻게 되는가'는 재지 못한다. 재하려면 reload 순간에 실제로
|
||||
전송 중인 요청이 있어야 한다.
|
||||
|
||||
장치
|
||||
845KB 짜리 관리 콘솔 번들을 --limit-rate 20k 로 내려받는다.
|
||||
응답을 일부러 느리게 읽어 요청을 ~42초 동안 살아 있게 만든다.
|
||||
대상: https://auth.hyeonworks.com/resources/55yjq/admin/keycloak.v2/assets/main-BbID33M6.js
|
||||
----------------------------------------------------------------
|
||||
[대조군: 주입 없이 1회]
|
||||
코드=200 받은바이트=845361 총시간=41.392198s 연결수=1 실효속도=20423B/s
|
||||
기대 크기 845361 / 실제 845361 bytes
|
||||
|
||||
판정 기준 (주입 시 이 값들과 비교한다)
|
||||
· 코드 200 + 크기 845361 = 진행 중이던 요청이 끝까지 살아남았다(graceful)
|
||||
· 코드 000 또는 크기 부족 = reload 가 진행 중이던 연결을 끊었다
|
||||
· 연결수 2 이상 = 중간에 끊겨 curl 이 다시 붙었다
|
||||
@@ -0,0 +1,112 @@
|
||||
D-4 — 갱신은 되는데 nginx 가 집지 않는다: 배포 훅 부재
|
||||
=========================================================
|
||||
수집: 2026-09-04 17:2x KST · test-server (sudo 없이 읽을 수 있는 범위)
|
||||
|
||||
발단
|
||||
----
|
||||
사용자가 `sudo certbot renew --force-renewal` 을 실행했다고 알려왔다.
|
||||
그런데 밖에서 본 인증서가 바뀌지 않았다.
|
||||
|
||||
serial=0520BB6416D569E26697B1691440F523B853
|
||||
notBefore=Sep 3 00:47:23 2026 GMT ← 어제 것 그대로
|
||||
notAfter=Dec 2 00:47:22 2026 GMT
|
||||
|
||||
일련번호 감시 161표본(약 13분) 동안 단 한 번도 바뀌지 않았다.
|
||||
|
||||
[증거 1] nginx 는 reload 된 적이 없다
|
||||
--------------------------------------
|
||||
$ ps -eo pid,ppid,etimes,lstart,args | grep nginx
|
||||
585 1 80529 Thu Sep 3 19:00:39 2026 nginx: master process /usr/bin/nginx
|
||||
586 585 80529 Thu Sep 3 19:00:39 2026 nginx: worker process
|
||||
|
||||
읽는 법 — nginx 의 reload 는 마스터를 유지한 채 **워커만 새로 띄운다.**
|
||||
· 마스터 585, 워커 586 = 마스터 기동 직후의 첫 fork
|
||||
· 둘의 lstart 가 같고 etimes 도 같다(80529초 = 22.4시간)
|
||||
→ reload 가 한 번도 없었다. 22.4시간 전 기동 그대로다.
|
||||
|
||||
인증서 파일이 새로 써졌더라도, nginx 는 기동 시점에 읽어 메모리에 들고 있다.
|
||||
reload 가 없으면 **옛 인증서를 계속 서빙한다.**
|
||||
|
||||
[증거 2] ★ 갱신 유닛에 reload 가 없다
|
||||
--------------------------------------
|
||||
$ systemctl cat certbot-renew.service
|
||||
# /usr/lib/systemd/system/certbot-renew.service
|
||||
[Unit]
|
||||
Description=Renew certificates acquired via Certbot
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/certbot -q renew
|
||||
PrivateTmp=true
|
||||
|
||||
`ExecStart` 가 전부다. **ExecStartPost 도, --deploy-hook 도 없다.**
|
||||
배포판(Arch)이 넣어준 기본 유닛이 그렇다.
|
||||
|
||||
$ systemctl cat certbot-renew.timer
|
||||
OnCalendar=*-*-* 00/12:00:00
|
||||
RandomizedDelaySec=12h
|
||||
Persistent=true
|
||||
|
||||
[증거 3] 타이머는 정상 동작한다 — 그래서 더 위험하다
|
||||
------------------------------------------------------
|
||||
$ systemctl status certbot-renew.service
|
||||
Active: inactive (dead) since Fri 2026-09-04 17:04:11 KST
|
||||
Process: 28452 ExecStart=/usr/bin/certbot -q renew (code=exited, status=0/SUCCESS)
|
||||
|
||||
$ journalctl -u certbot-renew.service --since today
|
||||
Sep 04 03:19:39 Starting Renew certificates acquired via Certbot...
|
||||
Sep 04 03:19:41 Finished Renew certificates acquired via Certbot.
|
||||
Sep 04 17:04:09 Starting Renew certificates acquired via Certbot...
|
||||
Sep 04 17:04:11 Finished Renew certificates acquired via Certbot.
|
||||
|
||||
오늘 두 번 돌았고 두 번 다 status=0/SUCCESS 다. 만료까지 88일 남아 실제
|
||||
갱신은 하지 않았으므로 **아직은** 아무 문제가 없다.
|
||||
|
||||
[증거 4] nginx 가 무엇을 물고 있나
|
||||
-----------------------------------
|
||||
$ grep -rn ssl_certificate /etc/nginx/
|
||||
/etc/nginx/sites-available/keycloak-lab:18: ssl_certificate /etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem;
|
||||
/etc/nginx/sites-available/keycloak-lab:19: ssl_certificate_key /etc/letsencrypt/live/auth.hyeonworks.com/privkey.pem;
|
||||
|
||||
`live/` 는 심볼릭 링크다. certbot 이 갱신하면 링크가 새 `archive/` 파일을
|
||||
가리키도록 바뀐다 — **파일 경로는 그대로인데 내용이 바뀐다.** 그래서 nginx
|
||||
설정은 고칠 필요가 없고, 바로 그 때문에 "설정이 그대로니 괜찮다"고 착각하기 쉽다.
|
||||
필요한 것은 설정 변경이 아니라 **reload** 다.
|
||||
|
||||
무엇을 확인하지 못했나
|
||||
----------------------
|
||||
`/etc/letsencrypt/renewal-hooks/deploy/` 에 스크립트가 있으면 유닛 파일과
|
||||
무관하게 실행된다. 이 디렉터리는 root 전용이라 읽지 못했다.
|
||||
|
||||
$ ls -laR /etc/letsencrypt/renewal-hooks/
|
||||
ls: cannot access '/etc/letsencrypt/renewal-hooks/': Permission denied
|
||||
|
||||
따라서 두 갈래가 남는다.
|
||||
(a) 강제 갱신이 실패했다 → 파일도 안 바뀌었고 reload 도 없었다
|
||||
(b) 강제 갱신이 성공했다 → 파일은 바뀌었는데 훅이 없어 reload 가 안 됐다
|
||||
|
||||
(b) 라면 이 실험대에서 가장 값진 발견이다. **"갱신 성공"과 "새 인증서 서빙"이
|
||||
다른 사건**이라는 것을, 88일 뒤가 아니라 지금 잡은 것이기 때문이다.
|
||||
|
||||
가리는 방법 — root 권한 한 번:
|
||||
sudo certbot certificates # notAfter 가 오늘+90일이면 (b)
|
||||
sudo ls -la /etc/letsencrypt/archive/auth.hyeonworks.com/
|
||||
sudo tail -60 /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
곁다리로 확인한 것 — CT 로그로는 가릴 수 없다
|
||||
-----------------------------------------------
|
||||
발급 사실은 Certificate Transparency 에 남으므로 sudo 없이 확인할 수 있을 것
|
||||
같았다. 실제로 서빙 중인 인증서에는 SCT 가 2개 박혀 있다.
|
||||
|
||||
CT Precertificate SCTs:
|
||||
Log ID: C2:31:7E:57:...:52:CD Timestamp: Sep 3 01:45:53.183 2026 GMT
|
||||
Log ID: 46:AF:86:3D:...:50:5F Timestamp: Sep 3 01:45:53.352 2026 GMT
|
||||
|
||||
그런데 crt.sh 는 이 이름을 모른다.
|
||||
|
||||
$ curl -s 'https://crt.sh/?q=auth.hyeonworks.com&output=json'
|
||||
[] ← 0건
|
||||
$ curl -s 'https://crt.sh/?q=hyeonworks.com&output=json'
|
||||
13건, 최신 not_before=2026-08-11 ← auth 는 없다
|
||||
|
||||
**인증서에 SCT 가 박혀 있다는 것과 crt.sh 가 그것을 색인했다는 것은 다르다.**
|
||||
관측 도구가 진실의 부분집합만 본다는, A-2 의 `up` 지표와 같은 종류의 함정이다.
|
||||
@@ -0,0 +1,66 @@
|
||||
D-4 — in-flight 감시에서 나온 76건 실패: 서버 탓이 아니다
|
||||
============================================================
|
||||
수집: 2026-09-04 · dev 머신에서 실행한 감시 로그
|
||||
|
||||
무엇이 보였나
|
||||
-------------
|
||||
42초짜리 in-flight 요청을 연달아 돌리는 감시에서, 91건 중 76건이 실패했다.
|
||||
|
||||
08:13:40 코드=200 바이트=845361 시간=41.041830 연결수=1
|
||||
08:14:22 코드=200 바이트=845361 시간=42.338482 연결수=1
|
||||
08:15:04 코드=000 바이트=0 시간=0.001148 연결수=0 ← 여기부터
|
||||
08:15:04 코드=000 바이트=0 시간=0.001140 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000055 연결수=0
|
||||
... (76건, 전부 08:15:04)
|
||||
08:15:04 코드=200 바이트=845361 시간=42.236496 연결수=1 ← 곧바로 복귀
|
||||
08:15:47 코드=200 바이트=845361 시간=42.327129 연결수=1
|
||||
|
||||
이걸 "갱신 중 진행 중이던 요청이 끊겼다"로 읽으면 안 되는 이유
|
||||
----------------------------------------------------------------
|
||||
1. **같은 순간 폴링은 멀쩡했다.** 0.2초 간격 폴링의 08:15:00–08:15:20 구간
|
||||
표본 49건이 전부 200이다. 같은 호스트, 같은 TLS, 같은 머신이다.
|
||||
|
||||
08:15:00.24 200 0.092491
|
||||
08:15:01.15 200 0.099177
|
||||
08:15:02.38 200 0.078729
|
||||
... 49건 / 비200 0건
|
||||
|
||||
2. **연결수=0 이다.** curl 이 TCP 연결을 시도조차 못 했다는 뜻이다.
|
||||
서버가 연결을 끊었다면 연결수는 1이고 바이트는 0보다 크다.
|
||||
|
||||
3. **시간이 0.00005초다.** 50마이크로초. DNS 조회조차 이보다 오래 걸린다.
|
||||
요청이 나가기 전에 로컬에서 실패했다.
|
||||
|
||||
4. **76건이 1초 안에 몰렸다.** 실패가 즉시 반환되니 while 루프가 폭주한 것이다.
|
||||
시간축에 퍼진 장애가 아니라 순간의 스파이크다.
|
||||
|
||||
5. **재현되지 않는다.**
|
||||
같은 URL 100회 연속 → 실패 0/100
|
||||
DNS 해석 200회 → 실패 0/200
|
||||
URL 유효성 → 코드=200 크기=845361, 콘솔이 참조하는 경로와 동일
|
||||
|
||||
6. **nginx 는 그 시각에 아무 일도 하지 않았다.** 마스터·워커가 22.4시간째
|
||||
같은 프로세스다(07 참조). reload 도 재시작도 없었다.
|
||||
|
||||
결론
|
||||
----
|
||||
**로컬(dev 머신) 쪽 일시적 원인이며, 서버 가용성 사건이 아니다.**
|
||||
정확한 원인은 특정하지 못했다 — curl 을 `-s` 로 돌려 오류 메시지를 버렸고,
|
||||
종료 코드도 기록하지 않았기 때문이다.
|
||||
|
||||
고친 것
|
||||
-------
|
||||
감시를 종료 코드까지 남기는 형태로 교체했다. 다음에 같은 일이 생기면
|
||||
curl 의 종료 코드(6=DNS, 7=connect, 35=TLS ...)로 원인이 바로 나온다.
|
||||
실패 시 1초 쉬게 해 루프 폭주도 막았다.
|
||||
|
||||
R=$(curl -s --limit-rate 20k -o /dev/null -w "..." "$URL" 2>/dev/null); E=$?
|
||||
echo "$T $R curl종료=$E"
|
||||
[ $E -ne 0 ] && sleep 1
|
||||
|
||||
남기는 교훈
|
||||
-----------
|
||||
측정 장치가 실패했을 때 **왜 실패했는지 남기지 않으면, 그 실패를 대상 탓으로
|
||||
돌릴지 장치 탓으로 돌릴지 판단할 근거가 없다.** 여기서는 대조 폴링이 같은
|
||||
시각에 멀쩡했다는 사실 하나로 겨우 갈랐다. 대조군이 없었다면 이 76건은
|
||||
"갱신 중 대규모 요청 실패"라는 그럴듯한 오보가 됐을 것이다.
|
||||
@@ -0,0 +1,564 @@
|
||||
08:10:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:10:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:11:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:18 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:12:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:04 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:09 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:13:55 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:41 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:14:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:15:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:16:55 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:41 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:17:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:18:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:18 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:19:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:20:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:21:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:22:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:23:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:24:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:25:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:26:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:27:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:28:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:29:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:30:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:31:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:32:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:33:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:18 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:34:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:04 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:09 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:35:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:36:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:18 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:37:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:04 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:09 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:38:55 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:41 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:39:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:40:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:41:55 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:41 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:42:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:43:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:44:55 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:41 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:45:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:46:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:04 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:09 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:47:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:48:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:18 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:49:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:04 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:50:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:52 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:51:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:18 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:23 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:28 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:33 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:38 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:52:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:04 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:09 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:14 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:45 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:50 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:53:55 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:00 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:21 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:26 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:31 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:36 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:41 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:54:57 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:02 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:07 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:12 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:17 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:43 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:48 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:53 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:55:58 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:03 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:08 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:13 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:19 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:24 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:29 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:34 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:39 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:44 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:49 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:54 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:56:59 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:05 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:10 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:15 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:20 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:25 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:30 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:35 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:40 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:46 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:51 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:57:56 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:01 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:06 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:11 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:16 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:22 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:27 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:32 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:37 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:42 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:47 serial=0520BB6416D569E26697B1691440F523B853 notAfter=Dec 2 00:47:22 2026 GMT
|
||||
08:58:52 serial=06C7CB6DF1DA8A6D7995D93C264BB9ECEA1D notAfter=Dec 3 07:21:52 2026 GMT
|
||||
08:58:52 ★ 일련번호 변경 감지 — 3분 더 재고 종료
|
||||
@@ -0,0 +1,177 @@
|
||||
08:10:51.60 200 0.104996
|
||||
08:10:51.91 200 0.070124
|
||||
08:10:52.19 200 0.131785
|
||||
... (중략)
|
||||
08:58:30.03 200 0.077607
|
||||
08:58:30.32 200 0.109888
|
||||
08:58:30.64 200 0.195213
|
||||
08:58:31.06 200 0.103103
|
||||
08:58:31.38 200 0.079529
|
||||
08:58:31.67 200 0.187888
|
||||
08:58:32.07 200 0.194786
|
||||
08:58:32.48 200 0.192114
|
||||
08:58:32.89 200 0.108582
|
||||
08:58:33.22 200 0.079331
|
||||
08:58:33.51 200 0.189853
|
||||
08:58:33.92 200 0.189635
|
||||
08:58:34.33 200 0.195752
|
||||
08:58:34.74 200 0.195164
|
||||
08:58:35.15 200 0.078307
|
||||
08:58:35.45 200 0.102306
|
||||
08:58:35.76 200 0.193694
|
||||
08:58:36.18 200 0.193912
|
||||
08:58:36.58 200 0.079270
|
||||
08:58:36.88 200 0.100873
|
||||
08:58:37.20 200 0.077209
|
||||
08:58:37.49 200 0.102600
|
||||
08:58:37.81 200 0.195354
|
||||
08:58:38.22 200 0.194041
|
||||
08:58:38.63 200 0.079332
|
||||
08:58:38.93 200 0.077710
|
||||
08:58:39.22 200 0.073483
|
||||
08:58:39.51 200 0.126482
|
||||
08:58:39.86 200 0.196844
|
||||
08:58:40.27 200 0.189230
|
||||
08:58:40.68 200 0.089921
|
||||
08:58:40.98 200 0.080912
|
||||
08:58:41.28 200 0.093971
|
||||
08:58:41.60 200 0.191146
|
||||
08:58:42.00 200 0.079236
|
||||
08:58:42.30 200 0.105411
|
||||
08:58:42.62 200 0.195868
|
||||
08:58:43.03 200 0.147224
|
||||
08:58:43.40 200 0.136670
|
||||
08:58:43.75 200 0.191708
|
||||
08:58:44.16 200 0.084091
|
||||
08:58:44.46 200 0.079146
|
||||
08:58:44.75 200 0.114239
|
||||
08:58:45.08 200 0.078791
|
||||
08:58:45.38 200 0.074542
|
||||
08:58:45.67 200 0.078430
|
||||
08:58:45.97 200 0.073271
|
||||
08:58:46.26 200 0.081292
|
||||
08:58:46.55 200 0.086169
|
||||
08:58:46.86 200 0.078664
|
||||
08:58:47.16 200 0.077433
|
||||
08:58:47.45 200 0.076830
|
||||
08:58:47.74 200 0.078261
|
||||
08:58:48.04 200 0.082249
|
||||
08:58:48.34 200 0.077844
|
||||
08:58:48.64 200 0.084788
|
||||
08:58:48.94 200 0.080198
|
||||
08:58:49.24 200 0.078426
|
||||
08:58:49.53 200 0.078641
|
||||
08:58:49.82 200 0.080504
|
||||
08:58:50.12 200 0.079685
|
||||
08:58:50.42 200 0.079559
|
||||
08:58:50.71 200 0.078883
|
||||
08:58:51.01 200 0.077754
|
||||
08:58:51.30 200 0.078970
|
||||
08:58:51.60 200 0.084448
|
||||
08:58:51.90 200 0.131753
|
||||
08:58:52.25 200 0.197813
|
||||
08:58:52.66 200 0.091437
|
||||
08:58:52.97 200 0.199400
|
||||
08:58:53.39 200 0.085250
|
||||
08:58:53.69 200 0.084521
|
||||
08:58:53.99 200 0.072331
|
||||
08:58:54.28 200 0.081943
|
||||
08:58:54.58 200 0.113594
|
||||
08:58:54.92 200 0.185589
|
||||
08:58:55.32 200 0.200308
|
||||
08:58:55.74 200 0.098051
|
||||
08:58:56.05 200 0.086943
|
||||
08:58:56.36 200 0.192842
|
||||
08:58:56.77 200 0.178977
|
||||
08:58:57.17 200 0.083091
|
||||
08:58:57.47 200 0.194195
|
||||
08:58:57.88 200 0.147293
|
||||
08:58:58.24 200 0.149510
|
||||
08:58:58.61 200 0.088007
|
||||
08:58:58.91 200 0.190298
|
||||
08:58:59.32 200 0.199024
|
||||
08:58:59.73 200 0.183439
|
||||
08:59:00.13 200 0.206752
|
||||
08:59:00.55 200 0.179475
|
||||
08:59:00.95 200 0.089502
|
||||
08:59:01.25 200 0.096302
|
||||
08:59:01.57 200 0.203361
|
||||
08:59:01.99 200 0.175288
|
||||
08:59:02.38 200 0.200164
|
||||
08:59:02.80 200 0.157565
|
||||
08:59:03.17 200 0.081179
|
||||
08:59:03.47 200 0.133562
|
||||
08:59:03.82 200 0.207667
|
||||
08:59:04.24 200 0.156695
|
||||
08:59:04.61 200 0.126136
|
||||
08:59:04.95 200 0.185645
|
||||
08:59:05.36 200 0.197049
|
||||
08:59:05.77 200 0.090621
|
||||
08:59:06.08 200 0.182576
|
||||
08:59:06.48 200 0.107587
|
||||
08:59:06.80 200 0.176183
|
||||
08:59:07.19 200 0.076604
|
||||
08:59:07.48 200 0.112886
|
||||
08:59:07.81 200 0.197961
|
||||
08:59:08.23 200 0.197695
|
||||
08:59:08.64 200 0.192117
|
||||
08:59:09.05 200 0.086968
|
||||
08:59:09.36 200 0.073667
|
||||
08:59:09.64 200 0.107286
|
||||
08:59:09.97 200 0.187141
|
||||
08:59:10.37 200 0.196110
|
||||
08:59:10.78 200 0.080634
|
||||
08:59:11.08 200 0.101278
|
||||
08:59:11.40 200 0.190454
|
||||
08:59:11.81 200 0.195550
|
||||
08:59:12.22 200 0.084865
|
||||
08:59:12.52 200 0.097978
|
||||
08:59:12.84 200 0.188273
|
||||
08:59:13.24 200 0.078268
|
||||
08:59:13.54 200 0.098529
|
||||
08:59:13.85 200 0.196250
|
||||
08:59:14.26 200 0.198583
|
||||
08:59:14.67 200 0.193794
|
||||
08:59:15.08 200 0.142313
|
||||
08:59:15.44 200 0.142774
|
||||
08:59:15.80 200 0.203481
|
||||
08:59:16.22 200 0.190197
|
||||
08:59:16.62 200 0.193118
|
||||
08:59:17.03 200 0.191270
|
||||
08:59:17.44 200 0.190572
|
||||
08:59:17.85 200 0.159825
|
||||
08:59:18.23 200 0.115453
|
||||
08:59:18.56 200 0.212529
|
||||
08:59:18.99 200 0.178715
|
||||
08:59:19.38 200 0.373160
|
||||
08:59:19.98 200 0.114451
|
||||
08:59:20.31 200 0.198672
|
||||
08:59:20.72 200 0.186258
|
||||
08:59:21.12 200 0.103469
|
||||
08:59:21.44 200 0.197932
|
||||
08:59:21.86 200 0.077019
|
||||
08:59:22.15 200 0.180685
|
||||
08:59:22.55 200 0.203363
|
||||
08:59:22.97 200 0.197513
|
||||
08:59:23.38 200 0.196509
|
||||
08:59:23.80 200 0.094951
|
||||
08:59:24.11 200 0.175434
|
||||
08:59:24.50 200 0.372545
|
||||
08:59:25.10 200 0.077048
|
||||
08:59:25.39 200 0.077420
|
||||
08:59:25.69 200 0.138478
|
||||
08:59:26.04 200 0.190167
|
||||
08:59:26.45 200 0.192613
|
||||
08:59:26.86 200 0.161352
|
||||
08:59:27.24 200 0.081419
|
||||
08:59:27.54 200 0.131994
|
||||
08:59:27.88 200 0.202003
|
||||
08:59:28.30 200 0.186137
|
||||
08:59:28.71 200 0.091572
|
||||
08:59:29.02 200 0.077290
|
||||
08:59:29.31 200 0.090913
|
||||
08:59:29.62 200 0.198752
|
||||
... (중략)
|
||||
09:01:10.29 200 0.105354
|
||||
09:01:10.62 200 0.173389
|
||||
09:01:11.00 200 0.191564
|
||||
@@ -0,0 +1,146 @@
|
||||
08:10:51 코드=200 바이트=845361 시간=42.335582 연결수=1
|
||||
08:11:33 코드=200 바이트=845361 시간=42.328216 연결수=1
|
||||
08:12:16 코드=200 바이트=845361 시간=42.332256 연결수=1
|
||||
08:12:58 코드=200 바이트=845361 시간=42.327378 연결수=1
|
||||
08:13:40 코드=200 바이트=845361 시간=41.041830 연결수=1
|
||||
08:14:22 코드=200 바이트=845361 시간=42.338482 연결수=1
|
||||
08:15:04 코드=000 바이트=0 시간=0.001148 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001140 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001124 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000055 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000080 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000077 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001167 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000048 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000096 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000039 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000083 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000075 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000041 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000061 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001141 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000078 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000053 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000083 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000099 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000083 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001164 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001106 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000074 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000087 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000072 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000085 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000085 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000048 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000046 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001147 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000044 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000053 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000076 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000043 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000091 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000074 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000049 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000051 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000087 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000091 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000095 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000055 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000076 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000077 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000088 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000085 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000092 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000080 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000085 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001157 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000048 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001097 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000060 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000080 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000087 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000048 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000081 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000084 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000087 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001153 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000053 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000088 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000052 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000085 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000084 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000080 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000079 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.001106 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000051 연결수=0
|
||||
08:15:04 코드=000 바이트=0 시간=0.000056 연결수=0
|
||||
08:15:04 코드=200 바이트=845361 시간=42.236496 연결수=1
|
||||
08:15:47 코드=200 바이트=845361 시간=42.327129 연결수=1
|
||||
08:16:29 코드=200 바이트=845361 시간=41.442808 연결수=1
|
||||
08:17:10 코드=200 바이트=845361 시간=42.332025 연결수=1
|
||||
08:17:53 코드=200 바이트=845361 시간=40.434517 연결수=1
|
||||
08:18:33 코드=200 바이트=845361 시간=41.438410 연결수=1
|
||||
08:19:15 코드=200 바이트=845361 시간=42.334617 연결수=1
|
||||
08:19:57 코드=200 바이트=845361 시간=42.333846 연결수=1
|
||||
08:20:39 코드=200 바이트=845361 시간=42.232748 연결수=1
|
||||
08:21:22 코드=200 바이트=845361 시간=42.324095 연결수=1
|
||||
08:22:04 코드=200 바이트=845361 시간=42.331593 연결수=1
|
||||
08:22:46 코드=200 바이트=845361 시간=41.626941 연결수=1
|
||||
08:23:28 코드=200 바이트=845361 시간=42.330280 연결수=1
|
||||
08:24:59 코드=200 바이트=845361 시간=42.331694 연결수=1 curl종료=0
|
||||
08:25:42 코드=200 바이트=845361 시간=42.333930 연결수=1 curl종료=0
|
||||
08:26:24 코드=200 바이트=845361 시간=41.839874 연결수=1 curl종료=0
|
||||
08:27:06 코드=200 바이트=845361 시간=41.834401 연결수=1 curl종료=0
|
||||
08:27:48 코드=200 바이트=845361 시간=41.840212 연결수=1 curl종료=0
|
||||
08:28:30 코드=200 바이트=845361 시간=41.032736 연결수=1 curl종료=0
|
||||
08:29:11 코드=200 바이트=845361 시간=41.433394 연결수=1 curl종료=0
|
||||
08:29:52 코드=200 바이트=845361 시간=42.325976 연결수=1 curl종료=0
|
||||
08:30:34 코드=200 바이트=845361 시간=42.037070 연결수=1 curl종료=0
|
||||
08:31:16 코드=200 바이트=845361 시간=42.343058 연결수=1 curl종료=0
|
||||
08:31:59 코드=200 바이트=845361 시간=41.837942 연결수=1 curl종료=0
|
||||
08:32:41 코드=200 바이트=845361 시간=42.318577 연결수=1 curl종료=0
|
||||
08:33:23 코드=200 바이트=845361 시간=42.336079 연결수=1 curl종료=0
|
||||
08:34:05 코드=200 바이트=845361 시간=42.328392 연결수=1 curl종료=0
|
||||
08:34:48 코드=200 바이트=845361 시간=41.839243 연결수=1 curl종료=0
|
||||
08:35:30 코드=200 바이트=845361 시간=42.339658 연결수=1 curl종료=0
|
||||
08:36:12 코드=200 바이트=845361 시간=42.330835 연결수=1 curl종료=0
|
||||
08:36:54 코드=200 바이트=845361 시간=41.844755 연결수=1 curl종료=0
|
||||
08:37:36 코드=200 바이트=845361 시간=41.442783 연결수=1 curl종료=0
|
||||
08:38:18 코드=200 바이트=845361 시간=42.334462 연결수=1 curl종료=0
|
||||
08:39:00 코드=200 바이트=845361 시간=42.331275 연결수=1 curl종료=0
|
||||
08:39:42 코드=200 바이트=845361 시간=41.243768 연결수=1 curl종료=0
|
||||
08:40:23 코드=200 바이트=845361 시간=41.837874 연결수=1 curl종료=0
|
||||
08:41:05 코드=200 바이트=845361 시간=42.336582 연결수=1 curl종료=0
|
||||
08:41:48 코드=200 바이트=845361 시간=42.327934 연결수=1 curl종료=0
|
||||
08:42:30 코드=200 바이트=845361 시간=42.333559 연결수=1 curl종료=0
|
||||
08:43:12 코드=200 바이트=845361 시간=41.841294 연결수=1 curl종료=0
|
||||
08:43:54 코드=200 바이트=845361 시간=42.329699 연결수=1 curl종료=0
|
||||
08:44:37 코드=200 바이트=845361 시간=41.845127 연결수=1 curl종료=0
|
||||
08:45:18 코드=200 바이트=845361 시간=42.040360 연결수=1 curl종료=0
|
||||
08:46:00 코드=200 바이트=845361 시간=41.845192 연결수=1 curl종료=0
|
||||
08:46:42 코드=200 바이트=845361 시간=42.327749 연결수=1 curl종료=0
|
||||
08:47:25 코드=200 바이트=845361 시간=41.837216 연결수=1 curl종료=0
|
||||
08:48:06 코드=200 바이트=845361 시간=42.329675 연결수=1 curl종료=0
|
||||
08:48:49 코드=200 바이트=845361 시간=42.036368 연결수=1 curl종료=0
|
||||
08:49:31 코드=200 바이트=845361 시간=42.341275 연결수=1 curl종료=0
|
||||
08:50:13 코드=200 바이트=845361 시간=42.332664 연결수=1 curl종료=0
|
||||
08:50:56 코드=200 바이트=845361 시간=42.334345 연결수=1 curl종료=0
|
||||
08:51:38 코드=200 바이트=845361 시간=41.837146 연결수=1 curl종료=0
|
||||
08:52:20 코드=200 바이트=845361 시간=42.328092 연결수=1 curl종료=0
|
||||
08:53:02 코드=200 바이트=845361 시간=42.344341 연결수=1 curl종료=0
|
||||
08:53:44 코드=200 바이트=845361 시간=42.332296 연결수=1 curl종료=0
|
||||
08:54:27 코드=200 바이트=845361 시간=41.839230 연결수=1 curl종료=0
|
||||
08:55:09 코드=200 바이트=845361 시간=42.336469 연결수=1 curl종료=0
|
||||
08:55:51 코드=200 바이트=845361 시간=42.336864 연결수=1 curl종료=0
|
||||
08:56:33 코드=200 바이트=845361 시간=42.043518 연결수=1 curl종료=0
|
||||
08:57:15 코드=200 바이트=845361 시간=42.340137 연결수=1 curl종료=0
|
||||
08:57:58 코드=200 바이트=845361 시간=42.335696 연결수=1 curl종료=0
|
||||
08:58:40 코드=200 바이트=845361 시간=40.840349 연결수=1 curl종료=0
|
||||
08:59:21 코드=200 바이트=845361 시간=42.340130 연결수=1 curl종료=0
|
||||
09:00:03 코드=200 바이트=845361 시간=41.841100 연결수=1 curl종료=0
|
||||
@@ -0,0 +1,41 @@
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Found the following certs:
|
||||
Certificate Name: auth.hyeonworks.com
|
||||
Serial Number: 6c7cb6df1da8a6d7995d93c264bb9ecea1d
|
||||
Key Type: ECDSA
|
||||
Identifiers: auth.hyeonworks.com app1.hyeonworks.com app2.hyeonworks.com
|
||||
Expiry Date: 2026-12-03 07:21:52+00:00 (VALID: 89 days)
|
||||
Certificate Path: /etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem
|
||||
Private Key Path: /etc/letsencrypt/live/auth.hyeonworks.com/privkey.pem
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
=== renewal-hooks ===
|
||||
/etc/letsencrypt/archive/auth.hyeonworks.com/:
|
||||
total 48
|
||||
drwxr-xr-x 2 root root 4096 2026-09-04 17:22:13.508658811 +0900 .
|
||||
drwx------ 3 root root 4096 2026-09-03 10:47:40.915270972 +0900 ..
|
||||
-rw-r--r-- 1 root root 1359 2026-09-03 10:47:40.915923507 +0900 cert1.pem
|
||||
-rw-r--r-- 1 root root 1359 2026-09-04 17:22:13.508494637 +0900 cert2.pem
|
||||
-rw-r--r-- 1 root root 3523 2026-09-03 10:47:40.916215769 +0900 chain1.pem
|
||||
-rw-r--r-- 1 root root 3523 2026-09-04 17:22:13.508658811 +0900 chain2.pem
|
||||
-rw-r--r-- 1 root root 4882 2026-09-03 10:47:40.916339551 +0900 fullchain1.pem
|
||||
-rw-r--r-- 1 root root 4882 2026-09-04 17:22:13.508821612 +0900 fullchain2.pem
|
||||
-rw------- 1 root root 241 2026-09-03 10:47:40.916079294 +0900 privkey1.pem
|
||||
-rw------- 1 root root 241 2026-09-04 17:22:13.507717972 +0900 privkey2.pem
|
||||
|
||||
/etc/letsencrypt/renewal-hooks/deploy/:
|
||||
total 8
|
||||
drwxr-xr-x 2 root root 4096 2026-09-03 10:46:54.658474560 +0900 .
|
||||
drwxr-xr-x 5 root root 4096 2026-09-03 10:46:54.658520760 +0900 ..
|
||||
|
||||
/etc/letsencrypt/renewal-hooks/post/:
|
||||
total 8
|
||||
drwxr-xr-x 2 root root 4096 2026-09-03 10:46:54.658505772 +0900 .
|
||||
drwxr-xr-x 5 root root 4096 2026-09-03 10:46:54.658520760 +0900 ..
|
||||
|
||||
/etc/letsencrypt/renewal-hooks/pre/:
|
||||
total 8
|
||||
drwxr-xr-x 2 root root 4096 2026-09-03 10:46:54.658474560 +0900 .
|
||||
drwxr-xr-x 5 root root 4096 2026-09-03 10:46:54.658520760 +0900 ..
|
||||
@@ -0,0 +1,99 @@
|
||||
D-4 판정 — 갱신은 성공했고, 36분 39초 동안 반영되지 않았다
|
||||
=============================================================
|
||||
수집: 2026-09-04 · 감시 08:10:51 ~ 09:02 UTC (KST-9)
|
||||
|
||||
════ 답 1 — "갱신 실패"가 아니라 "갱신됐는데 안 집었다" ════
|
||||
|
||||
07-renewal-hook-missing.txt 에서 두 갈래로 남겼던 것이 갈렸다.
|
||||
(a) 강제 갱신이 실패했다
|
||||
(b) 성공했는데 훅이 없어 reload 가 안 됐다
|
||||
→ ★ (b) 였다.
|
||||
|
||||
디스크 (12-certbot-state.txt)
|
||||
/etc/letsencrypt/archive/auth.hyeonworks.com/
|
||||
cert1.pem 2026-09-03 10:47:40 KST ← 처음 발급
|
||||
cert2.pem 2026-09-04 17:22:13 KST ← ★ 강제 갱신, 새로 써졌다
|
||||
fullchain2.pem 2026-09-04 17:22:13 KST
|
||||
privkey2.pem 2026-09-04 17:22:13 KST
|
||||
|
||||
Certificate Name: auth.hyeonworks.com
|
||||
Serial Number: 6c7cb6df1da8a6d7995d93c264bb9ecea1d
|
||||
Expiry Date: 2026-12-03 07:21:52+00:00 (VALID: 89 days)
|
||||
|
||||
밖에서 본 것 (09-serial-timeline.txt, 5초 간격 564표본)
|
||||
08:10:51 ~ 08:58:47 serial=0520BB...B853 notAfter=Dec 2 ← 옛 것
|
||||
08:58:52 serial=06C7CB...EA1D notAfter=Dec 3 ← 바뀐 순간
|
||||
|
||||
08:22:13 ~ 08:58:52 구간에서 옛 인증서로 관측된 횟수: 428회
|
||||
|
||||
시간 계산
|
||||
새 인증서 디스크 기록 : 08:22:13 UTC (= 17:22:13 KST, archive mtime)
|
||||
실제 서빙 시작 : 08:58:52 UTC (= 17:58:52 KST, nginx -s reload)
|
||||
────────────────────────────────────────────
|
||||
공백 : 2199초 = 36분 39초
|
||||
|
||||
그리고 이 36분은 **우연히 짧았을 뿐이다.** reload 를 시킨 것은 사람이지
|
||||
자동화가 아니다. 아무도 안 했다면 다음 nginx 재시작까지 — 즉 무기한 —
|
||||
옛 인증서를 계속 서빙했을 것이다.
|
||||
|
||||
왜 아무도 reload 하지 않았나 — 원인 세 가지가 겹쳤다
|
||||
1. certbot-renew.service 에 ExecStartPost 가 없다 (07 참조)
|
||||
2. /etc/letsencrypt/renewal-hooks/{deploy,post,pre}/ 가 전부 비어 있다
|
||||
deploy/ total 8 (. 과 .. 뿐)
|
||||
post/ total 8
|
||||
pre/ total 8
|
||||
3. certbot 에 nginx 플러그인이 없다 — 그래서 certbot 이 스스로 못 고친다
|
||||
Discovered plugins: dns-cloudflare, manual, null, standalone, webroot
|
||||
(certbot 5.7.0)
|
||||
|
||||
★ 세 경로 전부가 비어 있다. 하나라도 있었으면 자동으로 반영됐다.
|
||||
|
||||
왜 이게 88일 동안 안 보이나
|
||||
타이머는 정상이고 오늘도 두 번 status=0/SUCCESS 로 끝났다.
|
||||
만료 30일 전(= 약 58일 뒤)까지는 certbot 이 갱신 자체를 하지 않으므로
|
||||
"반영되지 않는다"는 결함이 발현할 기회가 없다. 발현하는 날 증상은
|
||||
**인증서 만료** 이고, 그때 로그는 여전히 SUCCESS 라고 적혀 있을 것이다.
|
||||
|
||||
════ 답 2 — reload 는 무중단이다 (측정됨) ════
|
||||
|
||||
계획서의 질문: "nginx reload 중 진행 중이던 요청은 어떻게 되는가"
|
||||
|
||||
[새 연결] 0.2초 폴링, 08:10:51 ~ 09:02
|
||||
전체 표본 8856건 / 비200 **0건**
|
||||
|
||||
응답시간 n 중앙 p95 최대
|
||||
─────────────────────────────────────────────────────────
|
||||
장기 평시 08:20~08:50 5398 98.0ms 205.7ms 1942.9ms
|
||||
reload 직전 2분56초 489 116.0ms 200.8ms 387.7ms
|
||||
reload 직후 2분08초 342 132.5ms 204.3ms 475.0ms
|
||||
|
||||
p95 가 205.7 → 204.3 으로 사실상 동일하고, 최대값은 오히려 낮다.
|
||||
10초 구간 중앙값은 reload 전후 모두 80~190ms 사이를 오간다(WiFi 잡음).
|
||||
→ **reload 로 인한 지연 증가는 관측되지 않았다.**
|
||||
|
||||
[진행 중이던 요청] 845KB 를 20k/s 로 받아 42초간 살려 둔 요청
|
||||
08:58:40 시작 · 소요 40.84초 → 08:59:21 종료
|
||||
reload 는 08:58:52, 즉 **요청 시작 12초 뒤 전송 한가운데**였다
|
||||
|
||||
코드=200 바이트=845361(전량) 연결수=1 curl종료=0
|
||||
|
||||
· 바이트가 전량이다 → 잘리지 않았다
|
||||
· 연결수가 1이다 → 중간에 끊겨 재연결한 것이 아니다
|
||||
· 옛 인증서로 시작한 연결이 새 워커 전환을 관통해 끝까지 갔다
|
||||
|
||||
in-flight 전체 50건 중 종료코드≠0 은 0건.
|
||||
(앞서 76건 실패는 로컬 아티팩트였다 — 08-inflight-artifact.txt)
|
||||
|
||||
════ 세 줄 요약 ════
|
||||
|
||||
1. **"갱신 성공"과 "새 인증서 서빙"은 다른 사건이다.** 36분 39초 동안
|
||||
디스크에는 새 인증서가, 네트워크에는 옛 인증서가 있었다. 428번 관측했다.
|
||||
|
||||
2. **reload 는 정말 무중단이었다.** 8856건 전부 200, p95 변화 없음,
|
||||
전송 한가운데였던 42초짜리 요청이 845361바이트를 온전히 받았다.
|
||||
D-4 문서가 "확인하지 않았으므로 그렇게 쓰면 안 된다"고 유보했던 명제가
|
||||
이제 측정으로 뒷받침된다.
|
||||
|
||||
3. **위험한 쪽은 reload 가 아니라 reload 를 부르는 사람이 없다는 것이다.**
|
||||
훅 디렉터리 3개가 전부 비었고, 유닛에 ExecStartPost 가 없고,
|
||||
nginx 플러그인도 없다. 그리고 그 상태로 타이머는 SUCCESS 를 찍는다.
|
||||
@@ -1,14 +1,28 @@
|
||||
# D-4 — 인증서 갱신 증거
|
||||
|
||||
2026-09-04 17:25–17:35 KST
|
||||
2026-09-04 17:25 – 18:02 KST
|
||||
해설: [`docs/experiment-d4-certificate-renewal.md`](../../experiment-d4-certificate-renewal.md)
|
||||
|
||||
| 파일 | 무엇을 보여주는가 |
|
||||
|---|---|
|
||||
| `01-certificate-state.txt` | SAN 3개(와일드카드 아님) · **체인 4단계, `Verify return code: 0`** · `certbot-renew.timer` enabled·active, 11시간 전 실행 · 88일 남음 · **`sudo: a password is required` 로 강제 갱신 불가** |
|
||||
| `05-control-no-injection.txt` | **대조군 1 — 잡음 바닥.** 0.2초 × 900회 / 180초 동안 **900전부 200, 오류 0**. 중앙 98ms · p95 195ms. **TLS 핸드셰이크 900/900** = 매 요청이 새 연결이다 |
|
||||
| `06-inflight-control.txt` | **대조군 2 — '진행 중이던 요청' 측정 장치.** 845KB 번들을 `--limit-rate 20k` 로 받아 요청을 **42초간 살려 둔다.** 무주입 시 코드 200 · 845361바이트 · 연결수 1 |
|
||||
|
||||
## 핵심 세 줄
|
||||
| `05-control-no-injection.txt` | **대조군 1 — 잡음 바닥.** 0.2초 × 900회 / 180초 동안 **900 전부 200, 오류 0**. 중앙 98ms · p95 195ms. **TLS 핸드셰이크 900/900** = 매 요청이 새 연결 |
|
||||
| `06-inflight-control.txt` | **대조군 2 — '진행 중이던 요청' 장치.** 845KB 를 `--limit-rate 20k` 로 받아 요청을 **42초간 살려 둔다.** 무주입 시 200 · 845361바이트 · 연결수 1 |
|
||||
| `07-renewal-hook-missing.txt` | **nginx 는 reload 된 적이 없다** — 마스터 585·워커 586 이 같은 시각 기동, 22.4시간째. 유닛은 `ExecStart=certbot -q renew` 가 전부. crt.sh 는 SCT 가 박힌 인증서를 0건으로 답한다 |
|
||||
| `08-inflight-artifact.txt` | **76건 실패는 서버 탓이 아니다** — 같은 순간 폴링 49건 전부 200, `연결수=0`, 50µs, 재현 0/100. 대조군이 오보를 막았다 |
|
||||
| `09-serial-timeline.txt` | **일련번호 564표본.** `08:10:51 ~ 08:58:47` 옛 것 → **`08:58:52` 새 것** |
|
||||
| `10-reload-poll-window.txt` | reload 전후 60초 새 연결 원문 — **비200 0건**, 최대 373ms |
|
||||
| `11-inflight-full.txt` | in-flight 전체 50건. **08:58:40 시작 요청이 08:58:52 reload 를 관통**해 845361바이트 전량 수신 |
|
||||
| `12-certbot-state.txt` | `cert2.pem` **09-04 17:22:13 기록됨** · `renewal-hooks/{deploy,post,pre}/` **셋 다 비었음** · 플러그인 목록에 nginx 없음 |
|
||||
| `13-verdict.txt` | **판정 전문** — 36분 39초 공백(428회 관측) + reload 무중단(8856건 0실패) |
|
||||
|
||||
1. **인증서가 이름 3개만 담는다.** B-7 에서 oauth2-proxy 를 올릴 호스트가 없어 Grafana 의 `app2` 를 빌려야 했던 실제 비용이 여기서 나왔다.
|
||||
2. **체인이 완전하다** — 단계가 4개이므로 `fullchain.pem` 을 쓰고 있다. 1개면 `cert.pem` 실수이며 캐시 없는 클라이언트에서만 깨진다.
|
||||
3. **강제 갱신은 못 했다.** 호스트 sudo 가 비밀번호를 요구한다. 타이머가 active 라는 것은 "갱신이 된다"의 확인이 아니다.
|
||||
## 핵심 다섯 줄
|
||||
|
||||
1. **「갱신 성공」과 「새 인증서 서빙」은 다른 사건이다.** 새 인증서가 디스크에 있는 채로 **36분 39초** 동안 옛 인증서를 서빙했고, 그 구간에서 **428번** 관측했다.
|
||||
2. **그 36분은 우연히 짧았다.** reload 를 시킨 것은 사람이다. 아무도 안 했다면 다음 nginx 재시작까지 무기한이었다.
|
||||
3. **원인이 셋 겹쳤다.** 유닛에 `ExecStartPost` 없음 · 훅 디렉터리 3개 전부 비었음 · certbot 에 nginx 플러그인 없음. 하나라도 있었으면 자동 반영됐다.
|
||||
4. **reload 자체는 무중단이었다.** 새 연결 8856건 전부 200, p95 205.7 → 204.3ms, 그리고 **전송 12초째에 reload 를 맞은 42초 요청이 845361바이트를 온전히** 받았다(연결수 1).
|
||||
5. **이 결함은 88일 동안 안 보인다.** 타이머는 오늘도 두 번 `SUCCESS` 로 끝났다. 만료 30일 전까지는 갱신 자체를 하지 않으므로 발현할 기회가 없고, 발현하는 날의 증상은 **인증서 만료**다 — 그날에도 로그는 `SUCCESS` 라고 적혀 있다.
|
||||
|
||||
@@ -1,9 +1,66 @@
|
||||
=== ★ Keycloak 에서 email 을 바꾼다 ===
|
||||
변경 시각: 15:27:52
|
||||
IdP 의 값: [ {
|
||||
IdP 의 값: "email" : "changed-labuser@example.com"
|
||||
IdP 의 값: } ]
|
||||
# B-4 ③ — IdP 의 클레임 변경은 언제 upstream 에 반영되는가
|
||||
#
|
||||
# 이 파일은 재수집본이다. 첫 수집본은 "이제 요청을 반복해 본다" 에서 끝났고,
|
||||
# 그 뒤의 12회 결과는 브라우저 콘솔에서만 보고 파일로 남기지 않았다.
|
||||
# 서브에이전트 감사가 "증거 없이 서 있는 결론" 으로 지적했고, 다시 측정했다.
|
||||
#
|
||||
# 수집 방법:
|
||||
# - 요청부: Playwright 로 연 브라우저에서 fetch('/api/echo') 를 반복.
|
||||
# oauth2-proxy 세션 쿠키가 HttpOnly 라 curl 로는 재현할 수 없어 브라우저를 썼다.
|
||||
# 아래 출력은 브라우저 콘솔이 돌려준 문자열 그대로다.
|
||||
# - 변경부·저장소 확인부: test-server 의 kubectl 출력 그대로.
|
||||
|
||||
=== IdP 쪽 세션과 oauth2-proxy 세션 ===
|
||||
Redis 세션: 1 개
|
||||
(세션은 로그인 시점의 클레임을 담고 있다 — 이제 요청을 반복해 본다)
|
||||
=== [1] 기준선 — 변경 전 (브라우저 fetch) ===
|
||||
2026-09-04T07:51:23.862Z req#1 HTTP 200 x-forwarded-email=labuser@example.com x-forwarded-preferred-username=labuser
|
||||
2026-09-04T07:51:24.304Z req#2 HTTP 200 x-forwarded-email=labuser@example.com x-forwarded-preferred-username=labuser
|
||||
2026-09-04T07:51:24.722Z req#3 HTTP 200 x-forwarded-email=labuser@example.com x-forwarded-preferred-username=labuser
|
||||
|
||||
=== [2] IdP 에서 email 을 바꾼다 (kubectl 출력) ===
|
||||
변경 시각(UTC): 2026-09-04T07:53:32.000Z
|
||||
IdP 의 값:
|
||||
[ {
|
||||
"email" : "changed-labuser@example.com"
|
||||
} ]
|
||||
oauth2-proxy 세션: 1 개 (그대로 살아 있다)
|
||||
|
||||
=== [시계 보정] 두 시계가 다르다 — 해석에 필요하다 ===
|
||||
개발 머신(브라우저 fetch 의 타임스탬프): 2026-09-04T07:52:20Z
|
||||
test-server (kubectl 출력의 타임스탬프): 2026-09-04T07:54:07Z
|
||||
→ test-server 가 약 107초 앞선다.
|
||||
브라우저 07:51:56 = 서버 07:53:43 이므로, 아래 12회는 변경(07:53:32) 11초 뒤다.
|
||||
|
||||
=== [3] 변경 후 12회 반복 (브라우저 fetch) ===
|
||||
2026-09-04T07:51:56.300Z req#1 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:56.864Z req#2 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:57.489Z req#3 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:58.018Z req#4 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:58.602Z req#5 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:59.217Z req#6 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:59.743Z req#7 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:52:00.342Z req#8 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:52:00.964Z req#9 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:52:01.574Z req#10 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:52:02.187Z req#11 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:52:02.719Z req#12 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
|
||||
→ 12회 · 약 6.4초 동안 전부 옛 값. 요청 횟수로는 반영되지 않는다.
|
||||
|
||||
=== [4] IdP 값은 이미 바뀌어 있었다 (대조) ===
|
||||
IdP: "email" : "changed-labuser@example.com"
|
||||
|
||||
=== [5] 세션을 지워 재인증을 강제한다 ===
|
||||
남은 oauth2-proxy 세션: 0 개
|
||||
(Keycloak SSO 는 살아 있으므로 조용히 재인증된다)
|
||||
|
||||
=== [6] 재인증 후 (브라우저 fetch) ===
|
||||
2026-09-04T07:53:01.121Z req#1 HTTP 200 x-forwarded-email=changed-labuser@example.com
|
||||
2026-09-04T07:53:01.456Z req#2 HTTP 200 x-forwarded-email=changed-labuser@example.com
|
||||
2026-09-04T07:53:01.785Z req#3 HTTP 200 x-forwarded-email=changed-labuser@example.com
|
||||
|
||||
=== 결론 ===
|
||||
변경 후 12회 요청(6.4초) → labuser@example.com (옛 값)
|
||||
세션 삭제 후 재인증 → changed-labuser@example.com (새 값)
|
||||
|
||||
→ 반영 시점은 요청 횟수가 아니라 세션이 새로 만들어지는가로 정해진다.
|
||||
--cookie-refresh 가 설정되어 있지 않으므로, 실제 운영에서는
|
||||
쿠키 만료(1시간) 또는 재인증까지 옛 값이 간다.
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
재현 절차 명령 실행 검증 — 문서에 적힌 명령을 그대로 돌려본 기록
|
||||
====================================================================
|
||||
수집: 2026-09-04, kc-lab-1 에서 sudo kubectl (호스트 test-server 경유)
|
||||
대상: 감사에서 "산문이라 재현 불가"로 지적된 명령들을 셸 실행형으로 바꾼 뒤,
|
||||
바꾼 형태가 실제로 도는지 확인한 것.
|
||||
|
||||
왜 이 파일이 있나
|
||||
------------------
|
||||
바꾼 명령을 돌려보지 않고 "재현 가능하게 고쳤다"고 쓰면, 감사가 잡아낸 바로
|
||||
그 실수(측정하지 않고 단언)를 반복하는 것이다. 그래서 실행 기록을 남긴다.
|
||||
그리고 실제로 이 검증에서 한 건이 깨졌다 — 아래 [실패] 항목.
|
||||
|
||||
환경
|
||||
----
|
||||
K0 = 10.42.1.142 (keycloak-0, kc-lab-2)
|
||||
K1 = 10.42.0.62 (keycloak-1, kc-lab-1)
|
||||
PW = keycloak-lab-secrets/KC_BOOTSTRAP_ADMIN_PASSWORD, 19자
|
||||
TE = /realms/master/protocol/openid-connect/token
|
||||
|
||||
[통과] 검증 1 — A-3 의 sid 추출 파이프라인
|
||||
-------------------------------------------
|
||||
문서 experiment-a3-database-crash.md 2단계에 넣은 파이프라인
|
||||
(access_token → 2번째 세그먼트 → '==' 패딩 → base64 -d → sid) 을 그대로 실행.
|
||||
|
||||
추출된 sid = YWfXBHn08DNujXvJ6QV1lMAd
|
||||
/tmp/sids 줄수 = 1
|
||||
|
||||
sid 는 UUID 가 아니라 24자 문자열이다. RPO 대조에서 IN 절에 넣을 때
|
||||
따옴표가 필요한 이유가 이것이다.
|
||||
|
||||
[통과] 검증 2 — A-6 단일 요청 지연 (각 15회)
|
||||
---------------------------------------------
|
||||
keycloak-0 평균 46 ms (대조군: PostgreSQL 과 같은 노드)
|
||||
keycloak-1 평균 86 ms (시험군: 노드 간 홉이 하나 더 있다)
|
||||
|
||||
주입 없는 평시 값이다. A-6 본문의 22.2초는 지연 주입 상태의 값이므로
|
||||
이 숫자와 직접 비교하면 안 된다. 여기서 확인한 것은 "명령이 돈다" 뿐이다.
|
||||
|
||||
[실패 → 수정] 검증 3 — 동시 20건 부하
|
||||
--------------------------------------
|
||||
처음에 쓴 형태:
|
||||
kubectl -n keycloak-lab run load --rm -i --restart=Never \
|
||||
--image=curlimages/curl:8.11.1 --quiet --command -- sh -c '... & ... wait'
|
||||
|
||||
결과: 출력이 도착하지 않고 세션이 그대로 끊겼다. 두 번 시도해서 두 번 다.
|
||||
일회성 파드(--rm -i)의 stdout 스트림이 20개 동시 자식 프로세스의 출력을
|
||||
잃는 문제이며, 이 실험 시리즈에서 이미 한 번 겪은 함정이다.
|
||||
내가 재현 절차를 고치면서 그 깨진 패턴을 다시 써넣었다.
|
||||
|
||||
고친 형태 — 상주 탐침 + 파드 안 파일 수집 + 한 번 cat:
|
||||
kubectl run a6-probe ... -- sleep 1800
|
||||
kubectl exec a6-probe -- sh -c '... >> /tmp/load ) & ... wait'
|
||||
kubectl exec a6-probe -- cat /tmp/load > /tmp/load.txt
|
||||
|
||||
결과:
|
||||
exit=0
|
||||
수집된 줄수 = 20 ← 20 이어야 한다. 스트림 방식은 여기서 샜다.
|
||||
상태코드별:
|
||||
20 200
|
||||
최대 지연 = 0.968958 s
|
||||
|
||||
[통과] 검증 4 — 풀 지표
|
||||
------------------------
|
||||
agroal_max_used_count{datasource="default"} 4.0
|
||||
agroal_active_count{datasource="default"} 0.0
|
||||
agroal_awaiting_count{datasource="default"} 0.0
|
||||
agroal_blocking_time_average_milliseconds{datasource="default"} 0.0
|
||||
|
||||
동시 20건에도 max_used 가 4 에 그치고 awaiting 이 0 이다.
|
||||
평시에는 풀이 병목이 아니라는 뜻이며, A-6 이 지연을 주입해야만
|
||||
경합이 나타난다고 적은 것과 일치한다.
|
||||
|
||||
남는 교훈
|
||||
---------
|
||||
"명령을 실행 가능하게 고쳤다"와 "고친 명령이 동작한다"는 다른 주장이다.
|
||||
검증 3 이 그 차이를 보여준다 — 문법적으로는 멀쩡했고, 실행하면 조용히 실패했다.
|
||||
@@ -9,9 +9,11 @@
|
||||
| `02-d2-rollback-same-schema.txt` | **스키마가 안 바뀌면 롤백이 된다** — 26.7.3 → 26.7.0 성공. 다만 전환 순간 `000` 1회(3초 타임아웃) |
|
||||
| `03-b4-role-propagation.txt` | **B-4 ③** IdP 에서 값을 바꿔도 **12회 요청·6초 동안 옛 값**. 세션 삭제 후 재인증에서야 새 값 |
|
||||
| `04-observability-gap.txt` | **B층에 관측이 없다** — Prometheus 는 keycloak·kubelet·node-exporter·prometheus 만 긁는다. Redis·BFF·PostgreSQL 지표가 0개 |
|
||||
| `05-command-reproducibility.txt` | **재현 절차 명령을 실제로 돌려본 기록.** 산문이던 측정 장치를 셸 실행형으로 바꾼 뒤 실행 검증 — 4건 중 1건(동시 20건 부하)이 **조용히 실패**했고 상주 탐침 방식으로 고쳐 20/20 수집 |
|
||||
|
||||
## 핵심 세 줄
|
||||
|
||||
1. **"롤백은 안 된다" 는 조건부였다.** 스키마가 바뀌었으면 안 되고, 안 바뀌었으면 된다 — D-2 의 결론을 정밀화한다.
|
||||
2. **role 변경은 요청 횟수와 무관하게 반영되지 않는다.** `--cookie-refresh` 가 없으면 쿠키 만료나 재인증까지 옛 값이 간다.
|
||||
3. **B층 실험에 Grafana 증거가 없는 이유가 확인됐다** — 관측 대상에 애초에 없다. 스크린샷이 없는 것이 아니라 지표가 없다.
|
||||
3. **바꾼 명령은 돌려봐야 안다.** 문법이 멀쩡해도 일회성 파드는 동시 출력에서 조용히 샜다 — 05 참조.
|
||||
4. **B층 실험에 Grafana 증거가 없는 이유가 확인됐다** — 관측 대상에 애초에 없다. 스크린샷이 없는 것이 아니라 지표가 없다.
|
||||
|
||||
@@ -471,7 +471,7 @@ kubectl -n keycloak-lab exec keycloak-0 -- \
|
||||
```sql
|
||||
select offline_flag, count(*) from offline_user_session group by offline_flag;
|
||||
select user_session_id, offline_flag, created_on, last_session_refresh
|
||||
from offline_user_session where user_session_id = '<sid>';
|
||||
from offline_user_session where user_session_id = '$SID';
|
||||
```
|
||||
|
||||
**이름이 내용을 배신하는 스키마다.** 운영에서 "온라인 세션이 DB 어디 있냐"를
|
||||
@@ -648,6 +648,6 @@ kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak \
|
||||
-c "select offline_flag, count(*) from offline_user_session group by offline_flag"
|
||||
|
||||
# 노드별 캐시 엔트리 (파드 안에서)
|
||||
curl -s http://<pod-ip>:9000/metrics \
|
||||
curl -s http://$(kubectl -n keycloak-lab get pod keycloak-0 -o jsonpath='{.status.podIP}'):9000/metrics \
|
||||
| grep 'approximate_entries_unique{cache="sessions"'
|
||||
```
|
||||
|
||||
@@ -446,7 +446,11 @@ kubectl -n keycloak-lab delete networkpolicy a1-block-jgroups-transport
|
||||
|
||||
```bash
|
||||
sudo conntrack -L | grep 7800
|
||||
sudo conntrack -D -p tcp -s <src> -d <dst> --sport <sp> --dport <dp>
|
||||
# 위 출력의 src/dst/sport/dport 를 그대로 넣는다. 한 줄로 하려면:
|
||||
sudo conntrack -L 2>/dev/null | grep 7800 | awk '{
|
||||
for(i=1;i<=NF;i++){ split($i,a,"="); t[a[1]]=a[2] }
|
||||
print "sudo conntrack -D -p tcp -s "t["src"]" -d "t["dst"]" --sport "t["sport"]" --dport "t["dport"]
|
||||
}' | sh
|
||||
```
|
||||
|
||||
### FD_SOCK2 와 포트 규약
|
||||
@@ -524,8 +528,14 @@ kubectl -n keycloak-lab get pods -o wide | grep keycloak # restarts=0 확인
|
||||
ssh kc-lab-1 'sudo conntrack -L | grep 7800'
|
||||
|
||||
# 4. conntrack 삭제 (양쪽 노드, 양쪽 방향). 반영까지 약 3분
|
||||
ssh kc-lab-1 'sudo conntrack -D -p tcp -s <k1ip> -d <k0ip> --sport <sp> --dport 7800'
|
||||
ssh kc-lab-2 'sudo conntrack -D -p tcp -s <k0ip> -d <k1ip> --sport 7800 --dport <sp>'
|
||||
# 노드마다 자기 conntrack 표에서 7800 튜플을 뽑아 그대로 지운다.
|
||||
# 방향(누가 client 인지)은 재시작마다 바뀐다 — 그래서 손으로 적으면 틀린다(A-5 에서 실제로 틀렸다).
|
||||
for N in kc-lab-1 kc-lab-2; do
|
||||
ssh $N "sudo conntrack -L 2>/dev/null | grep 7800 | awk '{
|
||||
for(i=1;i<=NF;i++){ split(\$i,a,\"=\"); t[a[1]]=a[2] }
|
||||
print \"sudo conntrack -D -p tcp -s \"t[\"src\"]\" -d \"t[\"dst\"]\" --sport \"t[\"sport\"]\" --dport \"t[\"dport\"]
|
||||
}' | sh"
|
||||
done
|
||||
|
||||
# 5. 분단 확인
|
||||
curl -s "http://localhost:19090/api/v1/query?query=vendor_cluster_size"
|
||||
|
||||
@@ -308,7 +308,9 @@ kubectl -n keycloak-lab wait --for=condition=Ready pod/a2-probe --timeout=120s
|
||||
kubectl -n keycloak-lab exec a2-probe -- sh -c \
|
||||
'curl -s -X POST http://<k0>:8080/realms/master/protocol/openid-connect/token \
|
||||
-d grant_type=password -d client_id=admin-cli \
|
||||
-d username=admin -d password=<pw> > /tmp/tok.json'
|
||||
-d username=admin -d password='"$PW"' > /tmp/tok.json'
|
||||
# PW=$(kubectl -n keycloak-lab get secret keycloak-lab-secrets \
|
||||
# -o jsonpath='{.data.KC_BOOTSTRAP_ADMIN_PASSWORD}' | base64 -d)
|
||||
|
||||
# 2. DB 정지
|
||||
kubectl -n keycloak-lab scale deployment/postgres --replicas=0
|
||||
|
||||
@@ -330,8 +330,21 @@ kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak \
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak \
|
||||
-c "delete from offline_user_session"
|
||||
|
||||
# 2. 로그인 루프 (호스트에서 백그라운드 exec — 파드 안 & 는 exec 종료와 함께 죽는다)
|
||||
kubectl -n keycloak-lab exec a2-probe -- sh -c '<로그인 반복, sid 를 /tmp/sids 에>' &
|
||||
# 2. 로그인 루프 — 호스트에서 백그라운드로 exec 한다.
|
||||
# 파드 안에서 ( ... ) & 로 띄우면 exec 세션이 끝날 때 같이 죽는다(실측).
|
||||
K0=$(kubectl -n keycloak-lab get pod keycloak-0 -o jsonpath='{.status.podIP}')
|
||||
kubectl -n keycloak-lab exec a2-probe -- sh -c "
|
||||
i=0
|
||||
while [ \$i -lt 200 ]; do
|
||||
R=\$(curl -s --max-time 5 -X POST http://$K0:8080/realms/master/protocol/openid-connect/token \
|
||||
-d grant_type=password -d client_id=admin-cli -d username=admin -d password=lab-admin-change-me)
|
||||
S=\$(echo \"\$R\" | sed -n 's/.*\"access_token\":\"\\([^\"]*\\)\".*/\\1/p' \
|
||||
| cut -d. -f2 | sed 's/\$/==/' | base64 -d 2>/dev/null \
|
||||
| sed -n 's/.*\"sid\":\"\\([^\"]*\\)\".*/\\1/p')
|
||||
[ -n \"\$S\" ] && echo \"\$S\" >> /tmp/sids
|
||||
i=\$((i+1))
|
||||
done" >/dev/null 2>&1 &
|
||||
LOOP=$!
|
||||
|
||||
# 3. 진짜 크래시 — 백엔드 프로세스에 SIGKILL
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- \
|
||||
@@ -340,9 +353,14 @@ kubectl -n keycloak-lab exec deploy/postgres -- \
|
||||
# 4. 주입이 걸렸는지 확인 — 이게 없으면 결과를 해석하지 않는다
|
||||
kubectl -n keycloak-lab logs deploy/postgres | grep -E "not properly shut down|redo"
|
||||
|
||||
# 5. 대조
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak -tAc \
|
||||
"select count(*) from offline_user_session where user_session_id in (<sid 목록>)"
|
||||
# 5. 대조 — 클라이언트가 200 을 받은 sid 를 그대로 IN 절로 만든다
|
||||
kill $LOOP 2>/dev/null
|
||||
kubectl -n keycloak-lab exec a2-probe -- cat /tmp/sids > /tmp/sids.txt
|
||||
TOTAL=$(wc -l < /tmp/sids.txt)
|
||||
IN=$(sed "s/^/'/; s/$/'/" /tmp/sids.txt | paste -sd,)
|
||||
FOUND=$(kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak -tAc \
|
||||
"select count(*) from offline_user_session where offline_flag='0' and user_session_id in ($IN)")
|
||||
echo "클라이언트 성공 $TOTAL / DB 존재 $FOUND / 유실 $((TOTAL-FOUND))"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -404,7 +404,7 @@ kubectl get node kc-lab-2 # 40초 뒤 NotReady
|
||||
kubectl -n keycloak-lab get pods -o wide # Running 인 채로 얼어 있다
|
||||
kubectl get node kc-lab-2 -o jsonpath='{.spec.taints}'
|
||||
# 5분 뒤 Terminating + 새 파드 Pending
|
||||
kubectl -n keycloak-lab describe pod <new-pod> | grep -A4 Events
|
||||
kubectl -n keycloak-lab describe pod $(kubectl -n keycloak-lab get pods -l app=postgres --field-selector=status.phase=Pending -o jsonpath='{.items[0].metadata.name}') | grep -A4 Events
|
||||
|
||||
# 4b 컨트롤 플레인 상실 — kubectl 이 죽으므로 노드에서 직접 본다
|
||||
virsh destroy kc-lab-1
|
||||
|
||||
@@ -318,14 +318,14 @@ JGroups 코디네이터는 **가장 오래된 멤버**다. 분단이 나면
|
||||
ssh kc-lab-1 'sudo conntrack -L | grep 7800'
|
||||
|
||||
# 2. 수신측 노드의 raw PREROUTING 에 넣는다 (filter 는 CNI 와 경쟁한다)
|
||||
ssh kc-lab-1 'sudo iptables -t raw -I PREROUTING 1 -p tcp -d <수신 파드IP> --dport 7800 -j DROP'
|
||||
ssh kc-lab-1 'sudo iptables -t raw -I PREROUTING 1 -p tcp -d <수신 파드IP> --dport 57800 -j DROP'
|
||||
ssh kc-lab-1 'sudo iptables -t raw -I PREROUTING 1 -p tcp -d $(kubectl -n keycloak-lab get pod keycloak-1 -o jsonpath='{.status.podIP}') --dport 7800 -j DROP'
|
||||
ssh kc-lab-1 'sudo iptables -t raw -I PREROUTING 1 -p tcp -d $(kubectl -n keycloak-lab get pod keycloak-1 -o jsonpath='{.status.podIP}') --dport 57800 -j DROP'
|
||||
|
||||
# 3. 걸렸는지 카운터로 확인 — 0 이면 해석 금지
|
||||
ssh kc-lab-1 'sudo iptables -t raw -L PREROUTING -n -v'
|
||||
|
||||
# 4. 양방향으로 하려면 반대 노드에도 (한 방향만으로는 자가 치유된다)
|
||||
ssh kc-lab-2 'sudo iptables -t raw -I PREROUTING 1 -p tcp -d <반대 파드IP> --dport 7800 -j DROP'
|
||||
ssh kc-lab-2 'sudo iptables -t raw -I PREROUTING 1 -p tcp -d $(kubectl -n keycloak-lab get pod keycloak-0 -o jsonpath='{.status.podIP}') --dport 7800 -j DROP'
|
||||
|
||||
# 5. 분단 확인
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak \
|
||||
|
||||
@@ -337,15 +337,51 @@ ssh kc-lab-2 '
|
||||
# 3. 걸렸는지 카운터로 확인 — Sent 가 0 이면 해석 금지
|
||||
ssh kc-lab-2 'sudo tc -s qdisc show dev flannel.1 | grep -A2 netem'
|
||||
|
||||
# 4. 단일 요청 지연 (대조군은 같은 노드의 keycloak-0)
|
||||
kubectl -n keycloak-lab run t --rm -i --restart=Never --image=curlimages/curl:8.11.1 \
|
||||
--command -- curl -s -o /dev/null -w '%{time_total}\n' -X POST http://<pod>:8080/realms/master/protocol/openid-connect/token ...
|
||||
# 변수 준비 — 아래 명령들이 이 값을 쓴다
|
||||
K0=$(kubectl -n keycloak-lab get pod keycloak-0 -o jsonpath='{.status.podIP}')
|
||||
K1=$(kubectl -n keycloak-lab get pod keycloak-1 -o jsonpath='{.status.podIP}')
|
||||
PW=$(kubectl -n keycloak-lab get secret keycloak-lab-secrets \
|
||||
-o jsonpath='{.data.KC_BOOTSTRAP_ADMIN_PASSWORD}' | base64 -d)
|
||||
TE=/realms/master/protocol/openid-connect/token
|
||||
|
||||
# 5. 동시 부하로 풀 고갈 재현
|
||||
# ( curl ... ) & 를 20개 띄우고 wait
|
||||
# 4. 상주 탐침을 먼저 띄운다.
|
||||
# ★ kubectl run --rm -i 로 20건을 동시에 돌리면 출력이 유실된다(실측: 20줄 중
|
||||
# 일부만 도착하거나 아예 끊긴다). 결과는 파드 안 파일에 모으고 한 번에 cat 한다.
|
||||
kubectl -n keycloak-lab run a6-probe --image=curlimages/curl:8.11.1 \
|
||||
--restart=Never --command -- sleep 1800
|
||||
kubectl -n keycloak-lab wait --for=condition=Ready pod/a6-probe --timeout=120s
|
||||
|
||||
# 6. 풀 지표
|
||||
curl -s http://<pod>:9000/metrics | grep -E '^agroal_(blocking_time|max_used|awaiting)'
|
||||
# 5. 단일 요청 지연 — 대조군(keycloak-0, DB 와 같은 노드) 대 시험군(keycloak-1)
|
||||
kubectl -n keycloak-lab exec a6-probe -- sh -c "
|
||||
for t in keycloak-0:$K0 keycloak-1:$K1; do
|
||||
n=\${t%%:*}; ip=\${t#*:}; T=0; i=0
|
||||
while [ \$i -lt 15 ]; do
|
||||
D=\$(curl -s -o /dev/null -w %{time_total} -X POST http://\$ip:8080$TE \
|
||||
-d grant_type=password -d client_id=admin-cli -d username=admin -d password=$PW)
|
||||
T=\$(echo \"\$T \$D\" | awk '{print \$1+\$2}'); i=\$((i+1))
|
||||
done
|
||||
echo \"\$n 평균 \$(echo \$T | awk '{printf \"%.0f\", \$1*1000/15}') ms\"
|
||||
done"
|
||||
|
||||
# 6. 동시 부하 20건 — & 로 띄우고 wait. 순차로 돌리면 풀 경합이 재현되지 않는다.
|
||||
kubectl -n keycloak-lab exec a6-probe -- sh -c "
|
||||
rm -f /tmp/load; i=0
|
||||
while [ \$i -lt 20 ]; do
|
||||
( curl -s -o /dev/null -w '%{http_code} %{time_total}\n' --max-time 60 \
|
||||
-X POST http://$K1:8080$TE -d grant_type=password -d client_id=admin-cli \
|
||||
-d username=admin -d password=$PW >> /tmp/load ) &
|
||||
i=\$((i+1))
|
||||
done
|
||||
wait"
|
||||
kubectl -n keycloak-lab exec a6-probe -- cat /tmp/load > /tmp/load.txt
|
||||
wc -l /tmp/load.txt # 20 이 아니면 수집이 샌 것이다
|
||||
awk '{print $1}' /tmp/load.txt | sort | uniq -c
|
||||
awk '{print $2}' /tmp/load.txt | sort -g | tail -1 # 최대 지연
|
||||
|
||||
# 7. 풀 지표 — 부하 직후에 읽어야 blocking_time 이 남아 있다
|
||||
kubectl -n keycloak-lab exec a6-probe -- sh -c \
|
||||
"curl -s http://$K1:9000/metrics \
|
||||
| grep -E '^agroal_(blocking_time_average|max_used_count|awaiting_count|active_count)'"
|
||||
|
||||
# 7. 해제
|
||||
ssh kc-lab-2 'sudo tc qdisc del dev flannel.1 root'
|
||||
|
||||
@@ -192,10 +192,23 @@ kubectl -n keycloak-lab run a8-probe --image=curlimages/curl:8.11.1 \
|
||||
--restart=Never --command -- sleep 3600
|
||||
kubectl -n keycloak-lab wait --for=condition=Ready pod/a8-probe --timeout=120s
|
||||
|
||||
# 로그인하고 토큰 보관
|
||||
# 변수 준비
|
||||
K0=$(kubectl -n keycloak-lab get pod keycloak-0 -o jsonpath='{.status.podIP}')
|
||||
PW=$(kubectl -n keycloak-lab get secret keycloak-lab-secrets \
|
||||
-o jsonpath='{.data.KC_BOOTSTRAP_ADMIN_PASSWORD}' | base64 -d)
|
||||
|
||||
# 로그인하고 refresh token 을 /tmp/rt 에, sid 를 /tmp/sid 에 보관.
|
||||
# ★ 아래 5번이 읽는 파일과 같은 이름이어야 한다 — 처음 문서는 /tmp/tok 에 쓰고
|
||||
# /tmp/rt 를 읽어서 빈 문자열을 보냈고, 그래도 400 이 아니라 통과한 것처럼 보였다.
|
||||
kubectl -n keycloak-lab exec a8-probe -- sh -c \
|
||||
'curl -s -X POST http://<pod>:8080/realms/master/protocol/openid-connect/token \
|
||||
-d grant_type=password -d client_id=admin-cli -d username=admin -d password=<pw> > /tmp/tok'
|
||||
"curl -s -X POST http://$K0:8080/realms/master/protocol/openid-connect/token \
|
||||
-d grant_type=password -d client_id=admin-cli -d username=admin -d password=$PW > /tmp/tok
|
||||
sed -n 's/.*\"refresh_token\":\"\\([^\"]*\\)\".*/\\1/p' /tmp/tok > /tmp/rt
|
||||
sed -n 's/.*\"access_token\":\"\\([^\"]*\\)\".*/\\1/p' /tmp/tok | cut -d. -f2 \
|
||||
| sed 's/\$/==/' | base64 -d 2>/dev/null \
|
||||
| sed -n 's/.*\"sid\":\"\\([^\"]*\\)\".*/\\1/p' > /tmp/sid
|
||||
echo \"rt \$(wc -c < /tmp/rt) bytes / sid \$(cat /tmp/sid)\""
|
||||
|
||||
|
||||
# 재시작 + 가용성 감시
|
||||
kubectl -n keycloak-lab rollout restart statefulset/keycloak
|
||||
@@ -203,12 +216,13 @@ kubectl -n keycloak-lab rollout status statefulset/keycloak --timeout=420s
|
||||
|
||||
# 세션 생존 확인
|
||||
kubectl -n keycloak-lab exec a8-probe -- sh -c \
|
||||
'curl -s -o /dev/null -w "%{http_code}\n" -X POST http://<pod>:8080/realms/master/protocol/openid-connect/token \
|
||||
'curl -s -o /dev/null -w "%{http_code}\n" -X POST http://'$K0':8080/realms/master/protocol/openid-connect/token \
|
||||
-d grant_type=refresh_token -d client_id=admin-cli -d refresh_token=$(cat /tmp/rt)'
|
||||
|
||||
# DB 대조
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak \
|
||||
-c "select user_session_id, created_on, last_session_refresh from offline_user_session where user_session_id='<sid>'"
|
||||
-c "select user_session_id, created_on, last_session_refresh from offline_user_session
|
||||
where offline_flag='0' and user_session_id='$(kubectl -n keycloak-lab exec a8-probe -- cat /tmp/sid)'"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -105,7 +105,7 @@ Bad Gateway
|
||||
파드 안에서 직접 받아 해결했다. **alpine 기반 JRE 이미지에 `wget` 이 있다.**
|
||||
|
||||
```bash
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuator/beans
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/beans
|
||||
```
|
||||
|
||||
---
|
||||
@@ -129,7 +129,7 @@ kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuat
|
||||
|
||||
```bash
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh config credentials \
|
||||
--server http://localhost:8080 --realm master --user admin --password <pw>
|
||||
--server http://localhost:8080 --realm master --user admin --password "$(kubectl -n keycloak-lab get secret keycloak-lab-secrets -o jsonpath='{.data.KC_BOOTSTRAP_ADMIN_PASSWORD}' | base64 -d)"
|
||||
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh create realms \
|
||||
-s realm=keycloak-patterns -s enabled=true -s accessTokenLifespan=60
|
||||
@@ -278,7 +278,7 @@ replica 를 늘리는 순간 로그인 자체가 실패한다.
|
||||
**무엇을 골랐는지는 실행 중인 인스턴스를 봐야 안다.**
|
||||
|
||||
```bash
|
||||
kubectl exec <pod> -- wget -qO- http://localhost:8083/actuator/beans
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/beans
|
||||
```
|
||||
|
||||
---
|
||||
@@ -320,7 +320,7 @@ kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh create rea
|
||||
kubectl apply -f deploy/lab/k8s/bff-redis.yaml
|
||||
|
||||
# 6. 자동구성 결과 — 파드 안에서 (프록시는 큰 응답에서 502)
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuator/beans > beans.json
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/beans > beans.json
|
||||
python3 -c "import json;d=json.load(open('beans.json'));[print(n,'->',i['type']) for n,i in
|
||||
list(d['contexts'].values())[0]['beans'].items() if 'AuthorizedClient' in i['type']]"
|
||||
```
|
||||
|
||||
@@ -122,7 +122,7 @@ value: http://echo.header-lab.svc:8081
|
||||
## 2. 자동구성이 실제로 바뀌었는가 — B-0 의 방법을 다시 쓴다
|
||||
|
||||
```bash
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuator/beans
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/beans
|
||||
```
|
||||
|
||||
```
|
||||
@@ -297,14 +297,14 @@ Q3 는 *"저장소를 직접 열어 refresh token 이 평문으로 남는지 확
|
||||
kubectl apply -f deploy/lab/k8s/bff-redis.yaml
|
||||
|
||||
# 4. 자동구성이 실제로 바뀌었는지 확인 (B-0 의 방법)
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuator/beans > after.json
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/beans > after.json
|
||||
# sessionRepository 가 RedisSessionRepository 인가
|
||||
# authorizedClientService 는 여전히 InMemory 인가 ← 이쪽이 핵심
|
||||
|
||||
# 5. Redis 를 직접 연다
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli --scan
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli hkeys "bff:session:sessions:<id>"
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli ttl "bff:session:sessions:<id>"
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli hkeys "bff:session:sessions:$(kubectl -n keycloak-lab exec deploy/redis -- redis-cli --scan --pattern 'bff:session:sessions:*' | grep -v expires | head -1 | sed 's/.*://')"
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli ttl "bff:session:sessions:$(kubectl -n keycloak-lab exec deploy/redis -- redis-cli --scan --pattern 'bff:session:sessions:*' | grep -v expires | head -1 | sed 's/.*://')"
|
||||
|
||||
# 6. 사용자 관점 확인
|
||||
# 브라우저로 https://app1.hyeonworks.com/bff/token-boundary
|
||||
|
||||
@@ -345,7 +345,7 @@ Spring Security 는 DDL 을 두 벌 제공한다.
|
||||
# + spring-boot-starter-jdbc, postgresql 의존성
|
||||
|
||||
# 2. 스키마 — PostgreSQL 판본을 써야 한다
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- sh -c \
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- sh -c \
|
||||
'unzip -p /app/app.jar BOOT-INF/lib/spring-security-oauth2-client-*.jar' > /dev/null
|
||||
# 실제로는 nested jar 를 풀어서 -postgres.sql 을 꺼낸다
|
||||
kubectl -n keycloak-lab exec -i deploy/postgres -- psql -U keycloak -d keycloak < oauth2-pg.sql
|
||||
|
||||
@@ -124,7 +124,7 @@ DB 로 확인했다.
|
||||
select us.user_session_id,
|
||||
(select count(*) from offline_client_session cs
|
||||
where cs.user_session_id = us.user_session_id) as client_sessions
|
||||
from offline_user_session us where us.user_session_id = '<sid>';
|
||||
from offline_user_session us where us.user_session_id = '$SID';
|
||||
```
|
||||
|
||||
```
|
||||
@@ -300,22 +300,37 @@ A-0 에서 Keycloak 자신이 `for no key update skip locked` 를 쓰는 이유
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh \
|
||||
update realms/keycloak-patterns -s revokeRefreshToken=true -s refreshTokenMaxReuse=0
|
||||
|
||||
# 2. refresh token 하나 확보 (direct grant)
|
||||
curl -s -X POST $KC -d grant_type=password -d client_id=bff-confidential \
|
||||
-d client_secret=bff-lab-secret -d username=labuser -d password=labpass -d scope=openid
|
||||
# 2. refresh token 하나 확보 (direct grant). 이후 단계가 전부 이 변수들을 쓴다.
|
||||
KC=http://keycloak.keycloak-lab.svc:8080/realms/keycloak-patterns/protocol/openid-connect/token
|
||||
R=$(curl -s -X POST $KC -d grant_type=password -d client_id=bff-confidential \
|
||||
-d client_secret=bff-lab-secret -d username=labuser -d password=labpass -d scope=openid)
|
||||
RT=$(echo "$R" | sed -n 's/.*"refresh_token":"\([^"]*\)".*/\1/p')
|
||||
SID=$(echo "$R" | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p' | cut -d. -f2 \
|
||||
| sed 's/$/==/' | base64 -d 2>/dev/null | sed -n 's/.*"sid":"\([^"]*\)".*/\1/p')
|
||||
echo "SID=$SID"
|
||||
|
||||
# 3. 동시에 5개 — & 와 wait 이 없으면 재현되지 않는다
|
||||
i=1; while [ $i -le 5 ]; do ( curl ... -d refresh_token=$RT > /tmp/c$i ) & i=$((i+1)); done; wait
|
||||
# 3. 동시에 5개 — & 와 wait 이 없으면 재현되지 않는다(순차로는 경합이 생기지 않는다)
|
||||
i=1
|
||||
while [ $i -le 5 ]; do
|
||||
( curl -s -o /tmp/c$i -w '%{http_code}\n' -X POST $KC \
|
||||
-d grant_type=refresh_token -d client_id=bff-confidential \
|
||||
-d client_secret=bff-lab-secret -d refresh_token=$RT ) &
|
||||
i=$((i+1))
|
||||
done
|
||||
wait
|
||||
|
||||
# 4. ★ 이긴 요청의 토큰을 다시 써본다 — 여기서 진짜 답이 나온다
|
||||
curl -s -o /dev/null -w '%{http_code}' -X POST $KC -d grant_type=refresh_token -d refresh_token=$NEW
|
||||
NEW=$(cat /tmp/c1 /tmp/c2 /tmp/c3 /tmp/c4 /tmp/c5 \
|
||||
| sed -n 's/.*"refresh_token":"\([^"]*\)".*/\1/p' | head -1)
|
||||
curl -s -o /dev/null -w '%{http_code}\n' -X POST $KC -d grant_type=refresh_token \
|
||||
-d client_id=bff-confidential -d client_secret=bff-lab-secret -d refresh_token=$NEW
|
||||
|
||||
# 5. 기제 확인 — client session 이 지워졌는지
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak -c \
|
||||
"select us.user_session_id,
|
||||
(select count(*) from offline_client_session cs
|
||||
where cs.user_session_id = us.user_session_id) as client_sessions
|
||||
from offline_user_session us where us.user_session_id = '<sid>'"
|
||||
from offline_user_session us where us.user_session_id = '$SID'"
|
||||
|
||||
# 6. 정책 비교 — revokeRefreshToken 과 refreshTokenMaxReuse 를 바꿔가며 3~5 반복
|
||||
```
|
||||
|
||||
@@ -213,11 +213,14 @@ Keycloak 의 role 이름은 임의 문자열이므로 **막을 수 있는 것이
|
||||
|
||||
| 항목 | 상태 |
|
||||
|---|---|
|
||||
| ③ role 변경 반영 시점 | **미측정.** oauth2-proxy 가 없어 "proxy session" 이 존재하지 않는다 |
|
||||
| ③ role 변경 반영 시점 | **측정 완료 →** [후속 문서 §3](experiment-followup-untested-items.md). IdP 에서 값을 바꿔도 **12회 요청·6초 동안 옛 값**, 세션 삭제 후 재인증에서야 새 값 |
|
||||
| ⑤ internal token 을 공통 경계로 이동 | **코드 변경.** `backend/` 의 SecurityConfig 에서 `permitAll` 경로를 좁히고 Filter 로 옮기는 작업 |
|
||||
| edge 에서 동명 헤더 덮어쓰기 | **nginx 설정 변경 필요** — `proxy_set_header X-Auth-Request-Roles ""` 로 먼저 지우고 다시 설정 |
|
||||
|
||||
**③ 은 oauth2-proxy 배포가 선행이며, 그것은 B-7 의 주제와 겹친다.**
|
||||
**③ 은 oauth2-proxy 배포가 선행이었고, 그것이 B-7 의 주제와 겹쳤다.**
|
||||
B-7 에서 oauth2-proxy 를 올린 뒤 후속 작업으로 측정했다 — 결론은
|
||||
**"요청 횟수와 무관하다. 세션이 새로 만들어져야 한다"** 이다.
|
||||
세션은 로그인 시점의 스냅샷이고, `--cookie-refresh` 가 없으면 갱신되지 않는다.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -246,8 +246,8 @@ kubectl -n keycloak-lab scale deployment/redis --replicas=0
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://app1.hyeonworks.com/bff/token-boundary # 000
|
||||
|
||||
# ② 왜 파드가 안 빠지는가 — 그룹별로 본다
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuator/health
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- wget -qO- http://localhost:8083/actuator/health/readiness
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/health
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:8083/actuator/health/readiness
|
||||
kubectl -n keycloak-lab get endpoints bff -o jsonpath='{.subsets[*].addresses[*].ip}'
|
||||
|
||||
# ③ 복구
|
||||
|
||||
@@ -237,7 +237,7 @@ curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $OLD" http://
|
||||
kcadm.sh get components -r keycloak-patterns --fields id,name,providerId
|
||||
|
||||
# 5. 제거하고 다시 확인 — 여기서 401 이 나와야 정상이다
|
||||
kcadm.sh delete components/<old-id> -r keycloak-patterns
|
||||
kcadm.sh delete components/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get components -r keycloak-patterns --fields id,name,providerId | grep -B2 '"name" : "rsa-generated"' | grep '"id"' | cut -d'"' -f4) -r keycloak-patterns
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -132,7 +132,7 @@ https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/aut
|
||||
|
||||
```bash
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh \
|
||||
create users/<user-id>/logout -r keycloak-patterns
|
||||
create users/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get users -r keycloak-patterns -q username=labuser --fields id --format csv --noquotes | tail -1)/logout -r keycloak-patterns
|
||||
```
|
||||
|
||||
```
|
||||
@@ -259,7 +259,7 @@ kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak -c
|
||||
|
||||
# 4. IdP 세션만 죽인다
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh \
|
||||
create users/<user-id>/logout -r keycloak-patterns
|
||||
create users/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get users -r keycloak-patterns -q username=labuser --fields id --format csv --noquotes | tail -1)/logout -r keycloak-patterns
|
||||
|
||||
# 5. 두 앱을 다시 연다 — 그대로 열리면 앱 세션이 독립적이라는 뜻
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
### IdP 쪽
|
||||
|
||||
```bash
|
||||
kcadm.sh get clients -r keycloak-patterns -q clientId=bff-confidential --fields attributes
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get clients -r keycloak-patterns -q clientId=bff-confidential --fields attributes
|
||||
```
|
||||
|
||||
```
|
||||
@@ -68,7 +68,7 @@ Spring Security 6.2+ 는 백채널 로그아웃을 지원하지만 **명시적
|
||||
## 2. IdP 쪽만 설정하고 시험했다
|
||||
|
||||
```bash
|
||||
kcadm.sh update clients/<id> -r keycloak-patterns \
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh update clients/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get clients -r keycloak-patterns -q clientId=bff --fields id --format csv --noquotes | tail -1) -r keycloak-patterns \
|
||||
-s 'attributes={"backchannel.logout.url":"https://app1.hyeonworks.com/logout/connect/back-channel/keycloak",
|
||||
"backchannel.logout.session.required":"true"}'
|
||||
```
|
||||
@@ -94,7 +94,7 @@ kcadm.sh update clients/<id> -r keycloak-patterns \
|
||||
Redis: 1 키
|
||||
|
||||
=== IdP 로그아웃 ===
|
||||
kcadm.sh create users/<id>/logout -r keycloak-patterns
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh create users/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get users -r keycloak-patterns -q username=labuser --fields id --format csv --noquotes | tail -1)/logout -r keycloak-patterns
|
||||
|
||||
=== 결과 ===
|
||||
keycloak-patterns 세션: 0 ← IdP 쪽은 끊겼다
|
||||
@@ -227,12 +227,12 @@ app2(oauth2-proxy)는 못 한다. **한 SSO 안에서 로그아웃 전파가 앱
|
||||
|
||||
```bash
|
||||
# 1. 현재 설정 확인 — 어느 쪽에도 없다
|
||||
kcadm.sh get clients -r keycloak-patterns -q clientId=bff-confidential --fields attributes
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get clients -r keycloak-patterns -q clientId=bff-confidential --fields attributes
|
||||
grep -rn "oidcLogout\|backchannel" bff/src/main/java/
|
||||
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://app1.hyeonworks.com/logout/connect/back-channel/keycloak
|
||||
|
||||
# 2. IdP 쪽 설정 — 점 표기는 안 먹는다. JSON 으로
|
||||
kcadm.sh update clients/<id> -r keycloak-patterns \
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh update clients/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get clients -r keycloak-patterns -q clientId=bff --fields id --format csv --noquotes | tail -1) -r keycloak-patterns \
|
||||
-s 'attributes={"backchannel.logout.url":"...","backchannel.logout.session.required":"true"}'
|
||||
|
||||
# 3. ★ 살아 있는 세션이 있는지 먼저 확인한다 (realm 을 join 해서)
|
||||
@@ -241,7 +241,7 @@ kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak -tA
|
||||
where r.name='keycloak-patterns' and us.offline_flag='0'"
|
||||
|
||||
# 4. 로그아웃하고 앱 세션을 본다
|
||||
kcadm.sh create users/<user-id>/logout -r keycloak-patterns
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh create users/$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh get users -r keycloak-patterns -q username=labuser --fields id --format csv --noquotes | tail -1)/logout -r keycloak-patterns
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli dbsize
|
||||
|
||||
# 5. 도달성 확인 — 클러스터 안에서 앱 공개 URL 로
|
||||
|
||||
@@ -114,7 +114,7 @@ ssh kc-lab-1 'sudo grep -c "lab-postgres-change-me" /var/lib/rancher/k3s/server/
|
||||
## 3. 파드 안에서는 환경변수다
|
||||
|
||||
```bash
|
||||
kubectl -n keycloak-lab exec <bff-pod> -- sh -c 'env | grep -iE "secret|password"'
|
||||
kubectl -n keycloak-lab exec $(kubectl -n keycloak-lab get pod -l app=bff --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') -- sh -c 'env | grep -iE "secret|password"'
|
||||
```
|
||||
|
||||
```
|
||||
@@ -223,7 +223,7 @@ ssh kc-lab-1 'sudo k3s secrets-encrypt status'
|
||||
ssh kc-lab-1 'sudo grep -c "lab-postgres-change-me" /var/lib/rancher/k3s/server/db/state.db'
|
||||
|
||||
# 5. 파드 안에서는 환경변수
|
||||
kubectl -n keycloak-lab exec <pod> -- sh -c 'env | grep -i secret'
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- sh -c 'env | grep -i secret'
|
||||
|
||||
# 6. 누가 읽을 수 있는가
|
||||
kubectl auth can-i get secrets -n keycloak-lab \
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||

|
||||
|
||||
**핵심 발견** — 갱신은 성공했는데 36분 39초 동안 반영되지 않았다.
|
||||
|
||||

|
||||
|
||||
> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md).
|
||||
> 실험대 전체 구조는 [`diagrams/lab-topology.svg`](diagrams/lab-topology.svg).
|
||||
|
||||
@@ -21,12 +25,19 @@
|
||||
|---|---|
|
||||
| 인증서 구성 | **SAN 3개** (`auth`/`app1`/`app2`), 와일드카드 아님 |
|
||||
| 체인 완결성 | **정상.** `Verify return code: 0 (ok)`, 4단계 |
|
||||
| 갱신 자동화 | **동작 중.** `certbot-renew.timer` enabled·active, 11시간 전 실행됨 |
|
||||
| 남은 기간 | **88일** (갱신까지 약 58일) |
|
||||
| **강제 갱신 실측** | **★ 못 했다.** `sudo: a password is required` |
|
||||
| 갱신 자동화 | 타이머는 **동작한다.** 오늘 두 번 `status=0/SUCCESS` |
|
||||
| **★ 갱신 반영** | **안 된다.** 새 인증서가 디스크에 있는 채로 **36분 39초** 동안 옛 인증서를 서빙했다 |
|
||||
| **★ reload 무중단** | **무중단이다.** 8856건 전부 200 · 전송 한가운데였던 42초 요청이 845361바이트 전량 수신 |
|
||||
|
||||
**측정한 것과 못 한 것을 나눠 적는다.** 못 한 것을 안 한 것처럼 쓰면
|
||||
이 기록 전체의 신뢰가 깎인다.
|
||||
### 한 문장으로
|
||||
|
||||
> **"갱신 성공"과 "새 인증서 서빙"은 다른 사건이다.**
|
||||
> 그리고 이 실험대에는 앞의 사건을 뒤의 사건으로 잇는 것이 **아무것도 없다.**
|
||||
|
||||
이게 왜 무서운가 — 이 결함은 **88일 동안 보이지 않는다.** 타이머는 정상이고
|
||||
매번 `SUCCESS` 로 끝난다. 만료 30일 전까지는 certbot 이 갱신 자체를 하지 않아
|
||||
"반영이 안 된다"는 사실이 발현할 기회가 없기 때문이다. 발현하는 날의 증상은
|
||||
**인증서 만료**이고, 그날에도 로그에는 `SUCCESS` 라고 적혀 있을 것이다.
|
||||
|
||||
---
|
||||
|
||||
@@ -112,87 +123,255 @@ certbot 은 **30일 남았을 때** 갱신한다. 지금 실행돼도 아무것
|
||||
|
||||
---
|
||||
|
||||
## 4. ★ 못 한 것 — 강제 갱신과 무중단 확인
|
||||
## 4. ★ 강제 갱신 — 두 개의 답
|
||||
|
||||
계획서의 D-4 는 이렇게 적혀 있었다.
|
||||
### 4-1. 먼저 대조군을 잡았다
|
||||
|
||||
주입 전에 평시를 재둔다. **이걸 건너뛰면 주입 결과를 해석할 수 없다** —
|
||||
A-6 에서 −41% 대조군을 "영향 없음"이라 적었던 것도, A-8 에서 표본 9개로
|
||||
무중단을 주장한 것도 같은 종류의 실수였다.
|
||||
|
||||
| 대조군 | 결과 |
|
||||
|---|---|
|
||||
| 새 연결 (0.2초 × 900회 / 180초) | **900 전부 200, 오류 0** · 중앙 98ms · p95 195ms |
|
||||
| 진행 중 요청 (845KB @ 20k/s) | 200 · 845361바이트 · 연결수 1 · **42.3초 완주** |
|
||||
|
||||
두 번째 장치가 왜 따로 필요했는가 — 첫 번째 폴링은 **TLS 핸드셰이크가
|
||||
900/900** 이다. 매 요청이 새 연결이라는 뜻이고, 그래서 "새 연결을 받아주는가"만
|
||||
잰다. 계획서가 물은 것은 **"진행 중이던 요청은 어떻게 되는가"** 이므로,
|
||||
reload 순간에 실제로 전송 중인 요청이 있어야 한다. 845KB 짜리 관리 콘솔
|
||||
번들을 일부러 느리게 받아 요청 하나를 42초 동안 살려 두었다.
|
||||
|
||||
### 4-2. 갱신은 성공했는데, 인증서가 바뀌지 않았다
|
||||
|
||||
`sudo certbot renew --force-renewal` 을 실행한 뒤에도 밖에서 본 인증서가
|
||||
그대로였다. 처음에는 갱신이 실패한 줄 알았다. 아니었다.
|
||||
|
||||
```
|
||||
디스크 (/etc/letsencrypt/archive/auth.hyeonworks.com/)
|
||||
cert1.pem 2026-09-03 10:47:40 KST 처음 발급
|
||||
cert2.pem 2026-09-04 17:22:13 KST ← 강제 갱신, 새로 써졌다
|
||||
|
||||
네트워크 (5초 간격 564표본)
|
||||
08:10:51 ~ 08:58:47 serial=0520BB…B853 notAfter=Dec 2 ← 옛 것
|
||||
08:58:52 serial=06C7CB…EA1D notAfter=Dec 3 ← 바뀐 순간
|
||||
```
|
||||
|
||||
| | 시각 (UTC) |
|
||||
|---|---|
|
||||
| 새 인증서 디스크 기록 | 08:22:13 |
|
||||
| 실제 서빙 시작 (`nginx -s reload`) | 08:58:52 |
|
||||
| **공백** | **2199초 = 36분 39초** |
|
||||
|
||||
그 사이 **428번** 옛 인증서로 관측됐다. 그리고 이 36분은 **우연히 짧았을
|
||||
뿐이다** — reload 를 시킨 것은 사람이지 자동화가 아니다. 아무도 안 했다면
|
||||
다음 nginx 재시작까지, 즉 무기한 옛 인증서를 서빙했을 것이다.
|
||||
|
||||
#### 개념 — 왜 파일이 바뀌어도 nginx 는 모르는가
|
||||
|
||||
**무엇인가.** nginx 는 `ssl_certificate` 가 가리키는 파일을 **기동 시점에
|
||||
한 번 읽어 메모리에 들고 있다.** 요청마다 디스크를 다시 보지 않는다.
|
||||
|
||||
**왜 여기 나오나.** certbot 은 `live/` 심볼릭 링크가 새 `archive/` 파일을
|
||||
가리키도록 바꾼다. **경로는 그대로인데 내용만 바뀐다.** 그래서 nginx 설정을
|
||||
고칠 필요가 없고, 바로 그 때문에 "설정이 그대로니 괜찮다"고 착각하기 쉽다.
|
||||
필요한 것은 설정 변경이 아니라 **reload** 다.
|
||||
|
||||
**없거나 틀리면.** 인증서가 만료되어 브라우저가 `NET::ERR_CERT_DATE_INVALID`
|
||||
를 띄운다. 그 시점에 디스크에는 멀쩡한 인증서가 들어 있고 갱신 로그도
|
||||
`SUCCESS` 다 — 그래서 원인을 찾는 데 오래 걸린다.
|
||||
|
||||
**확인.** nginx 는 reload 하면 마스터를 유지한 채 워커만 새로 띄운다.
|
||||
```bash
|
||||
ps -eo pid,ppid,etimes,lstart,args | grep nginx
|
||||
# 585 1 80529 Thu Sep 3 19:00:39 nginx: master process
|
||||
# 586 585 80529 Thu Sep 3 19:00:39 nginx: worker process
|
||||
# ↑ 워커가 마스터 기동 직후의 첫 fork(585→586) 그대로 22.4시간째
|
||||
# = reload 가 한 번도 없었다
|
||||
```
|
||||
|
||||
#### 원인은 하나가 아니라 셋이 겹쳤다
|
||||
|
||||
| # | 경로 | 상태 |
|
||||
|---|---|---|
|
||||
| 1 | `certbot-renew.service` 의 `ExecStartPost` | **없다** — `ExecStart=/usr/bin/certbot -q renew` 가 전부 |
|
||||
| 2 | `/etc/letsencrypt/renewal-hooks/{deploy,post,pre}/` | **셋 다 비어 있다** (`total 8`, `.` 과 `..` 뿐) |
|
||||
| 3 | certbot 의 nginx 플러그인 | **없다** — `dns-cloudflare, manual, null, standalone, webroot` |
|
||||
|
||||
**세 경로 전부가 비어 있다.** 하나라도 있었으면 자동으로 반영됐다.
|
||||
certbot 5.7.0 에서 확인한 값이다.
|
||||
|
||||
#### 고치는 법
|
||||
|
||||
```bash
|
||||
sudo certbot renew --force-renewal
|
||||
# 가장 단순한 방법 — deploy 훅 하나
|
||||
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOS'
|
||||
#!/bin/sh
|
||||
nginx -t && nginx -s reload
|
||||
EOS
|
||||
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
|
||||
```
|
||||
|
||||
**실행할 수 없었다.**
|
||||
`deploy/` 는 **실제로 갱신된 인증서가 있을 때만** 실행된다. `post/` 는 갱신
|
||||
여부와 무관하게 매번 돌므로, 하루 두 번 쓸데없이 reload 하게 된다.
|
||||
|
||||
**확인 방법** — 훅을 넣었다고 끝이 아니다. 다음 강제 갱신 때 `nginx` 워커
|
||||
PID 가 바뀌는지 봐야 한다. 이 실험이 그 확인 절차다.
|
||||
|
||||
### 4-3. reload 는 무중단이다 — 측정됨
|
||||
|
||||
계획서의 질문에 대한 답이다.
|
||||
|
||||
**새 연결** — 0.2초 폴링, 08:10:51 ~ 09:02, **전체 8856건 / 비200 0건**
|
||||
|
||||
| 구간 | n | 중앙 | p95 | 최대 |
|
||||
|---|---|---|---|---|
|
||||
| 장기 평시 08:20~08:50 | 5398 | 98.0ms | 205.7ms | 1942.9ms |
|
||||
| reload 직전 2분56초 | 489 | 116.0ms | 200.8ms | 387.7ms |
|
||||
| reload 직후 2분08초 | 342 | 132.5ms | **204.3ms** | 475.0ms |
|
||||
|
||||
p95 가 205.7 → 204.3 으로 **사실상 동일**하고 최대값은 오히려 낮다.
|
||||
10초 구간 중앙값은 reload 전후 모두 80~190ms 사이를 오간다 — WiFi 잡음이지
|
||||
reload 의 흔적이 아니다.
|
||||
|
||||
**진행 중이던 요청** — 여기가 계획서가 정확히 물은 지점이다.
|
||||
|
||||
```
|
||||
$ sudo -n -l
|
||||
sudo: a password is required
|
||||
$ sudo -n systemctl reload nginx
|
||||
sudo: a password is required
|
||||
08:58:40 요청 시작 (845KB @ 20k/s)
|
||||
08:58:52 ← nginx -s reload. 요청 시작 12초 뒤, 전송 한가운데
|
||||
08:59:21 종료: 코드=200 바이트=845361(전량) 연결수=1 curl종료=0
|
||||
```
|
||||
|
||||
**test-server 의 sudo 는 비밀번호를 요구한다.** 게스트(kc-lab-1/2)는 무암호라
|
||||
A층에서 `conntrack`·`tc` 를 자유롭게 썼는데, **호스트는 다르다.**
|
||||
|
||||
> **이 사실은 B-7 에서 처음 드러났다** — nginx 설정을 읽으려던 시도가 계속
|
||||
> 빈 결과였고, 그게 **sudo 의 조용한 실패**였다. 여기서 다시 확인된다.
|
||||
|
||||
### 그래서 답하지 못한 것
|
||||
|
||||
| 계획서의 항목 | 상태 |
|
||||
| 관측 | 읽는 법 |
|
||||
|---|---|
|
||||
| nginx reload 타이밍에 무중단인가 | **미측정** |
|
||||
| 갱신 중 진행 중이던 요청은 | **미측정** |
|
||||
| `certbot-renew.timer` 가 실제 갱신을 하는가 | **미측정** (58일 뒤에야 알 수 있다) |
|
||||
| 바이트가 전량이다 | 잘리지 않았다 |
|
||||
| **연결수가 1이다** | 중간에 끊겨 재연결한 게 아니다 |
|
||||
| 코드 200 | 옛 워커가 이 요청을 끝까지 책임졌다 |
|
||||
|
||||
### 이론적으로는 무엇을 기대하는가
|
||||
옛 인증서로 시작한 연결이 **새 워커 전환을 관통해** 끝까지 갔다.
|
||||
in-flight 전체 50건 중 종료코드 ≠ 0 은 **0건**이다.
|
||||
|
||||
```
|
||||
certbot renew → 새 인증서 파일 저장
|
||||
└─ deploy-hook: nginx -s reload
|
||||
└─ nginx 는 새 워커를 띄우고 옛 워커는 진행 중 요청을 끝낸 뒤 종료
|
||||
→ graceful. 진행 중 요청은 옛 인증서로 완결된다
|
||||
```
|
||||
> 문서가 "nginx 의 reload 는 설계상 무중단이지만 **확인하지 않았으므로 그렇게
|
||||
> 쓰면 안 된다**"고 유보했던 명제가, 이제 측정으로 뒷받침된다.
|
||||
> **그리고 유보가 옳았다** — 같은 자리에서 유보 없이 썼다면 맞았겠지만,
|
||||
> 바로 옆의 "갱신하면 반영된다"는 명제는 틀렸다. 어느 쪽이 틀릴지는 미리 알 수 없다.
|
||||
|
||||
**nginx 의 reload 는 설계상 무중단**이지만, **확인하지 않았으므로 그렇게
|
||||
쓰면 안 된다.** 이 실험대에서 반복해 배운 것이 바로 그것이다 —
|
||||
A-1 의 NetworkPolicy, A-3 의 `--grace-period=0`, B-5 의 AOF 모두
|
||||
**"그럴 것이다" 가 틀렸던 사례**다.
|
||||
### 4-4. 남은 미측정
|
||||
|
||||
---
|
||||
| 항목 | 상태 |
|
||||
|---|---|
|
||||
| `certbot-renew.timer` 가 **실제 갱신**을 하는가 | **미측정.** 약 58일 뒤에야 조건이 성립한다 |
|
||||
| deploy 훅을 넣으면 자동 반영되는가 | **미측정.** 훅은 아직 넣지 않았다 |
|
||||
|
||||
---
|
||||
|
||||
## 증거 파일
|
||||
|
||||
**증거 수집 시각: 2026-09-04 15:09 – 15:09 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||
**증거 수집: 2026-09-04 · 감시 08:10:51 – 09:02 UTC** (파일 mtime 기준)
|
||||
|
||||
| 파일 | 종류 |
|
||||
|---|---|
|
||||
| [`01-certificate-state.txt`](evidence/d4-certificate-renewal/01-certificate-state.txt) | 터미널 원문 |
|
||||
| 파일 | 종류 | 무엇을 보여주는가 |
|
||||
|---|---|---|
|
||||
| [`01-certificate-state.txt`](evidence/d4-certificate-renewal/01-certificate-state.txt) | 터미널 | SAN 3개 · 체인 4단계 `Verify return code: 0` |
|
||||
| [`05-control-no-injection.txt`](evidence/d4-certificate-renewal/05-control-no-injection.txt) | 터미널 | **대조군 1** — 900/900 200, 오류 0 · 핸드셰이크 900/900 |
|
||||
| [`06-inflight-control.txt`](evidence/d4-certificate-renewal/06-inflight-control.txt) | 터미널 | **대조군 2** — 42초 in-flight 장치, 845361바이트 완주 |
|
||||
| [`07-renewal-hook-missing.txt`](evidence/d4-certificate-renewal/07-renewal-hook-missing.txt) | 터미널 | nginx 워커 PID 로 본 "reload 없음" · 유닛에 `ExecStartPost` 없음 · crt.sh 로는 못 가림 |
|
||||
| [`08-inflight-artifact.txt`](evidence/d4-certificate-renewal/08-inflight-artifact.txt) | 터미널 | 76건 실패가 **로컬 아티팩트**임을 대조 폴링으로 가려낸 기록 |
|
||||
| [`09-serial-timeline.txt`](evidence/d4-certificate-renewal/09-serial-timeline.txt) | 터미널 | 일련번호 564표본 — 08:58:52 에 바뀌는 순간 |
|
||||
| [`10-reload-poll-window.txt`](evidence/d4-certificate-renewal/10-reload-poll-window.txt) | 터미널 | reload 전후 60초 새 연결 원문 (비200 0건) |
|
||||
| [`11-inflight-full.txt`](evidence/d4-certificate-renewal/11-inflight-full.txt) | 터미널 | in-flight 전체 — reload 를 관통한 08:58:40 요청 포함 |
|
||||
| [`12-certbot-state.txt`](evidence/d4-certificate-renewal/12-certbot-state.txt) | 터미널 | `certbot certificates` · `archive/` mtime · **훅 3개 디렉터리 전부 비었음** |
|
||||
| [`13-verdict.txt`](evidence/d4-certificate-renewal/13-verdict.txt) | 터미널 | **판정** — 36분 39초 공백 + reload 무중단, 수치 전량 |
|
||||
|
||||
파일별 상세는 [`evidence/d4-certificate-renewal/README.md`](evidence/d4-certificate-renewal/README.md).
|
||||
|
||||
## 5. 재현 절차 (명령어)
|
||||
|
||||
```bash
|
||||
# 1. 인증서 내용 — 밖에서 볼 수 있다
|
||||
echo | openssl s_client -connect auth.hyeonworks.com:443 -servername auth.hyeonworks.com 2>/dev/null \
|
||||
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 1. 인증서 내용 — 밖에서 볼 수 있다(sudo 불필요)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
for H in auth app1 app2; do
|
||||
echo "-- $H.hyeonworks.com"
|
||||
echo | openssl s_client -connect $H.hyeonworks.com:443 -servername $H.hyeonworks.com 2>/dev/null \
|
||||
| openssl x509 -noout -serial -dates -subject -ext subjectAltName
|
||||
done
|
||||
# 세 이름의 일련번호가 같으면 → 인증서 1장에 SAN 3개다.
|
||||
# B-7 이 네 번째 이름을 못 쓴 이유가 여기 있다.
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 2. 체인 완결성 — 단계가 1개면 cert.pem 을 쓴 것이다
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
echo | openssl s_client -connect auth.hyeonworks.com:443 -servername auth.hyeonworks.com 2>/dev/null \
|
||||
| grep -E "^ *[0-9] s:|Verify return code"
|
||||
| grep -E '^ *[0-9]+ s:|^ *i:|Verify return code'
|
||||
|
||||
# 3. 갱신 자동화
|
||||
systemctl list-timers certbot-renew.timer --no-pager
|
||||
systemctl is-enabled certbot-renew.timer
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 3. ★ 대조군을 먼저 잡는다 — 이걸 건너뛰면 주입 결과를 해석할 수 없다
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 3-a. 새 연결 가용성: 0.2초 × 900회 = 180초
|
||||
i=0
|
||||
while [ $i -lt 900 ]; do
|
||||
curl -s -o /dev/null -w '%{http_code} %{time_total} %{time_appconnect}\n' \
|
||||
--max-time 5 https://auth.hyeonworks.com/realms/master
|
||||
i=$((i+1)); sleep 0.2
|
||||
done > /tmp/d4-control.txt
|
||||
awk '{print $1}' /tmp/d4-control.txt | sort | uniq -c # 비200 이 몇 개인가
|
||||
|
||||
# 4. 강제 갱신 (sudo 필요 — 이 실험대에서는 불가)
|
||||
# 3-b. 진행 중 요청: 845KB 를 20k/s 로 받아 42초 동안 살려 둔다
|
||||
JS=$(curl -s https://auth.hyeonworks.com/admin/master/console/ \
|
||||
| grep -oE '/resources/[a-z0-9]+/admin/[^"]+\.js' | head -1)
|
||||
curl -s --limit-rate 20k -o /tmp/inflight.bin \
|
||||
-w '코드=%{http_code} 바이트=%{size_download} 시간=%{time_total} 연결수=%{num_connects}\n' \
|
||||
"https://auth.hyeonworks.com$JS"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 4. 감시를 켠다 — 일련번호가 바뀌면 3분 더 재고 스스로 멈춘다
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
BASE=$(echo | openssl s_client -connect auth.hyeonworks.com:443 \
|
||||
-servername auth.hyeonworks.com 2>/dev/null | openssl x509 -noout -serial | cut -d= -f2)
|
||||
rm -f /tmp/d4-stop
|
||||
|
||||
# 감시 0 — 일련번호. 바뀌는 순간이 nginx 가 새 인증서를 집은 순간이다
|
||||
setsid bash -c '
|
||||
BASE='"$BASE"'
|
||||
while [ ! -f /tmp/d4-stop ]; do
|
||||
S=$(echo | openssl s_client -connect auth.hyeonworks.com:443 \
|
||||
-servername auth.hyeonworks.com 2>/dev/null | openssl x509 -noout -serial -enddate | tr "\n" " ")
|
||||
echo "$(date -u +%H:%M:%S) $S"
|
||||
case "$S" in *"$BASE"*) ;; *) sleep 180; touch /tmp/d4-stop;; esac
|
||||
sleep 5
|
||||
done' > /tmp/d4-serial.txt 2>&1 < /dev/null &
|
||||
|
||||
# 감시 1 — 새 연결
|
||||
setsid bash -c '
|
||||
while [ ! -f /tmp/d4-stop ]; do
|
||||
echo "$(date -u +%H:%M:%S.%2N) $(curl -s -o /dev/null -w "%{http_code} %{time_total}" \
|
||||
--max-time 5 https://auth.hyeonworks.com/realms/master)"
|
||||
sleep 0.2
|
||||
done' > /tmp/d4-poll.txt 2>&1 < /dev/null &
|
||||
|
||||
# 감시 2 — 진행 중 요청을 끊김 없이 연달아 (reload 순간에 반드시 하나가 떠 있게)
|
||||
setsid bash -c '
|
||||
while [ ! -f /tmp/d4-stop ]; do
|
||||
echo "$(date -u +%H:%M:%S) $(curl -s --limit-rate 20k -o /dev/null \
|
||||
-w "코드=%{http_code} 바이트=%{size_download} 시간=%{time_total} 연결수=%{num_connects}" \
|
||||
https://auth.hyeonworks.com'"$JS"')"
|
||||
done' > /tmp/d4-inflight.txt 2>&1 < /dev/null &
|
||||
# ★ setsid 가 필요하다. 그냥 & 로 띄우면 부모 셸이 끝날 때 같이 죽는다
|
||||
# (A-3 에서 파드 안 & 가 exec 종료와 함께 죽은 것과 같은 함정이다).
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 5. 주입 — 여기만 sudo 가 필요하다
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
ssh test-server
|
||||
sudo certbot renew --force-renewal
|
||||
# 갱신 중 다른 창에서:
|
||||
# while true; do curl -s -o /dev/null -w '%{http_code} ' https://auth.hyeonworks.com/realms/master; sleep 1; done
|
||||
```
|
||||
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 6. 판정
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
grep -vE ' 200 ' /tmp/d4-poll.txt # 새 연결이 끊긴 순간 (대조군은 0건)
|
||||
grep -v '코드=200' /tmp/d4-inflight.txt # 진행 중 요청이 끊긴 순간
|
||||
grep -v "$BASE" /tmp/d4-serial.txt | head # 새 인증서가 서빙되기 시작한 시각
|
||||
```
|
||||
|
||||
## 6. 남긴 것
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
증거 [`docs/evidence/followup/`](evidence/followup/) ·
|
||||
2026-09-04 17:35–18:20 KST
|
||||
|
||||
23개 실험을 마치며 **세 항목을 "못 했다" 로 남겼다.** 그중 둘을 채우고,
|
||||
셋째(D-4 강제 갱신)는 권한이 필요해 별도로 진행한다.
|
||||
23개 실험을 마치며 **세 항목을 "못 했다" 로 남겼다. 이제 셋 다 채웠다.**
|
||||
셋째(D-4 강제 갱신)는 호스트 sudo 가 필요해 사람이 함께 실행했고,
|
||||
결과적으로 **이 세 항목 중 가장 큰 발견**이 거기서 나왔다.
|
||||
|
||||
---
|
||||
|
||||
@@ -17,6 +18,8 @@
|
||||
| **그리고 D-2 의 결론이 정밀해졌다** | **"롤백 불가" 는 조건부다** — 스키마가 바뀌었을 때만 |
|
||||
| **B-4 ③ role 변경 반영 시점** | **요청 횟수와 무관하다.** 세션이 새로 만들어져야 한다 |
|
||||
| **B층에 Grafana 증거가 없는 이유** | **관측 대상에 없다.** 안 찍은 것이 아니다 |
|
||||
| **D-4 강제 갱신** | **★ 갱신은 성공했는데 36분 39초 동안 반영되지 않았다** |
|
||||
| **D-4 reload 무중단** | **무중단이다.** 8856건 전부 200 · 전송 한가운데였던 요청이 전량 수신 |
|
||||
|
||||
---
|
||||
|
||||
@@ -130,30 +133,66 @@ B-4 를 할 때 **oauth2-proxy 가 아직 배포되지 않아** "proxy session"
|
||||
role 을 헤더로 내보내려면 추가 설정이 필요한데, **"IdP 의 클레임 변경이
|
||||
언제 반영되는가" 라는 질문은 어느 클레임이든 같다.**
|
||||
|
||||
1 · 3 단계는 **브라우저 콘솔**에서 실행한다. oauth2-proxy 쿠키가 HttpOnly 라
|
||||
curl 로는 로그인 상태를 재현할 수 없기 때문이다(그래서 셸이 아니라 JS 다).
|
||||
|
||||
```js
|
||||
// 1. 기준선 — 로그인된 app2 탭의 콘솔에서
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const r = await (await fetch('/api/echo')).text();
|
||||
console.log(new Date().toISOString(), r.match(/x-forwarded-email: (.*)/)[1]);
|
||||
}
|
||||
|
||||
// 3. 반복 요청 — 0.5초 간격으로 12번
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const r = await (await fetch('/api/echo')).text();
|
||||
console.log(new Date().toISOString(), r.match(/x-forwarded-email: (.*)/)[1]);
|
||||
await new Promise(s => setTimeout(s, 500));
|
||||
}
|
||||
```
|
||||
|
||||
2 단계는 셸에서:
|
||||
|
||||
```bash
|
||||
# 1. 기준선
|
||||
fetch('/api/echo') → x-forwarded-email = labuser@example.com
|
||||
|
||||
# 2. IdP 에서 바꾼다
|
||||
kcadm.sh update users/<id> -r keycloak-patterns -s email=CHANGED-labuser@example.com
|
||||
UID=$(kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh \
|
||||
get users -r keycloak-patterns -q username=labuser \
|
||||
--fields id --format csv --noquotes | tail -1)
|
||||
kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh \
|
||||
update users/$UID -r keycloak-patterns -s email=CHANGED-labuser@example.com
|
||||
|
||||
# 3. 반복 요청
|
||||
for (i=1..12) fetch('/api/echo') # 0.5초 간격
|
||||
# 4. Redis 세션을 지워 재인증을 강제한다 (반영 조건 확인)
|
||||
kubectl -n keycloak-lab exec deploy/redis -- redis-cli --scan --pattern 'oauth2-proxy*' \
|
||||
| xargs -r kubectl -n keycloak-lab exec deploy/redis -- redis-cli del
|
||||
```
|
||||
|
||||
### 결과 — 반영되지 않는다
|
||||
|
||||
```
|
||||
1: labuser@example.com
|
||||
2: labuser@example.com
|
||||
...
|
||||
12: labuser@example.com ← 12회 · 6초 동안 옛 값
|
||||
2026-09-04T07:51:56.300Z req#1 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
2026-09-04T07:51:56.864Z req#2 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
...
|
||||
2026-09-04T07:52:02.719Z req#12 HTTP 200 x-forwarded-email=labuser@example.com
|
||||
|
||||
→ 12회 · 6.4초 동안 전부 옛 값
|
||||
```
|
||||
|
||||
> **이 결과는 처음에 증거 파일로 남기지 않았다.** 브라우저 콘솔에서 보고
|
||||
> 문서에만 옮겨 적었고, 서브에이전트 감사가 "증거 없이 서 있는 결론" 으로
|
||||
> 지적했다. **다시 측정해
|
||||
> [`03-b4-role-propagation.txt`](evidence/followup/03-b4-role-propagation.txt)
|
||||
> 에 타임스탬프와 함께 남겼다.**
|
||||
>
|
||||
> 재측정 중 **두 시계가 107초 어긋나 있다**는 것도 드러났다 —
|
||||
> 브라우저(개발 머신)와 test-server 의 시각을 그대로 비교하면 안 되고,
|
||||
> 증거 파일에 보정값을 적어두었다.
|
||||
|
||||
세션을 지우고 재인증시키자
|
||||
|
||||
```
|
||||
재인증 후 email = changed-labuser@example.com
|
||||
2026-09-04T07:53:01.121Z req#1 HTTP 200 x-forwarded-email=changed-labuser@example.com
|
||||
2026-09-04T07:53:01.456Z req#2 HTTP 200 x-forwarded-email=changed-labuser@example.com
|
||||
2026-09-04T07:53:01.785Z req#3 HTTP 200 x-forwarded-email=changed-labuser@example.com
|
||||
```
|
||||
|
||||
### 개념 — 세션은 로그인 시점의 스냅샷이다
|
||||
@@ -222,31 +261,97 @@ for (i=1..12) fetch('/api/echo') # 0.5초 간격
|
||||
|
||||
---
|
||||
|
||||
## 5. 남은 것 — D-4 강제 갱신
|
||||
## 5. D-4 강제 갱신 — 셋째 항목, 그리고 가장 큰 발견
|
||||
|
||||
### 왜 못 했었나
|
||||
|
||||
```
|
||||
$ sudo -n -l
|
||||
sudo: a password is required
|
||||
```
|
||||
|
||||
**호스트 sudo 가 비밀번호를 요구해 `certbot renew --force-renewal` 과
|
||||
`systemctl reload nginx` 를 실행할 수 없다.** 사람이 함께 있어야 한다.
|
||||
호스트 sudo 가 비밀번호를 요구해 `certbot renew --force-renewal` 을 실행할 수
|
||||
없었다. 게스트(kc-lab-1/2)는 무암호라 A층에서 `conntrack`·`tc` 를 자유롭게
|
||||
썼는데 **호스트는 다르다.** 이 사실 자체가 B-7 에서 처음 드러났던 것이다 —
|
||||
nginx 설정을 읽으려던 시도가 계속 빈 결과였고, 그게 sudo 의 조용한 실패였다.
|
||||
|
||||
측정 계획은 준비되어 있다.
|
||||
### 방법 — 주입보다 대조군을 먼저
|
||||
|
||||
```bash
|
||||
# 측정 쪽 (내가 실행)
|
||||
while true; do
|
||||
printf '%s ' "$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 https://auth.hyeonworks.com/realms/master)"
|
||||
sleep 0.2
|
||||
done
|
||||
사람이 실행할 명령은 하나뿐이므로, **그 한 번을 헛되게 쓰지 않는 것**이
|
||||
관건이었다. 주입 전에 평시를 재두지 않으면 주입 중에 나온 값을 해석할 수 없다.
|
||||
|
||||
# 주입 쪽 (사람이 실행)
|
||||
sudo certbot renew --force-renewal
|
||||
| 대조군 | 결과 |
|
||||
|---|---|
|
||||
| 새 연결 (0.2초 × 900회 / 180초) | **900 전부 200, 오류 0** · 중앙 98ms · p95 195ms |
|
||||
| 진행 중 요청 (845KB @ 20k/s) | 200 · 845361바이트 · 연결수 1 · **42.3초 완주** |
|
||||
|
||||
두 번째 장치가 따로 필요했던 이유가 중요하다. 첫 번째 폴링은 **TLS
|
||||
핸드셰이크가 900/900** 이다 — 매 요청이 새 연결이라는 뜻이고, 그래서
|
||||
"새 연결을 받아주는가"만 잰다. 계획서가 물은 것은 **"진행 중이던 요청은
|
||||
어떻게 되는가"** 이므로, reload 순간에 실제로 전송 중인 요청이 있어야 한다.
|
||||
845KB 짜리 번들을 일부러 느리게 받아 요청 하나를 42초간 살려 두었다.
|
||||
|
||||
### 결과 ① — 갱신은 성공했는데 인증서가 바뀌지 않았다
|
||||
|
||||
```
|
||||
디스크 cert2.pem 2026-09-04 17:22:13 KST 기록됨
|
||||
네트워크 08:10:51 ~ 08:58:47 serial=0520BB…B853 (옛 것)
|
||||
08:58:52 serial=06C7CB…EA1D (새 것)
|
||||
```
|
||||
|
||||
**0.2초 간격으로 재는 이유** — 2절에서 1초 간격으로는 전환을 거의 못 잡았다.
|
||||
nginx reload 는 그보다 훨씬 짧을 것이므로 해상도를 올려야 한다.
|
||||
| | 시각 (UTC) |
|
||||
|---|---|
|
||||
| 새 인증서 디스크 기록 | 08:22:13 |
|
||||
| 실제 서빙 시작 (`nginx -s reload`) | 08:58:52 |
|
||||
| **공백** | **2199초 = 36분 39초** (그 사이 428회 관측) |
|
||||
|
||||
그리고 그 36분은 **우연히 짧았을 뿐이다** — reload 를 시킨 것은 사람이지
|
||||
자동화가 아니다. 원인이 셋 겹쳤고 **전부 비어 있었다.**
|
||||
|
||||
| | 상태 |
|
||||
|---|---|
|
||||
| `certbot-renew.service` 의 `ExecStartPost` | 없음 |
|
||||
| `renewal-hooks/{deploy,post,pre}/` | **셋 다 비었음** |
|
||||
| certbot 의 nginx 플러그인 | 없음 |
|
||||
|
||||
**이 결함은 88일 동안 보이지 않는다.** 타이머는 오늘도 두 번 `SUCCESS` 로
|
||||
끝났다. 만료 30일 전까지는 갱신 자체를 하지 않으므로 발현할 기회가 없고,
|
||||
발현하는 날의 증상은 **인증서 만료**다 — 그날에도 로그는 `SUCCESS` 다.
|
||||
|
||||
### 결과 ② — reload 는 무중단이다
|
||||
|
||||
**0.2초 간격으로 잰 이유** — 2절에서 1초 간격으로는 전환을 거의 못 잡았다.
|
||||
nginx reload 는 그보다 짧을 것이므로 해상도를 올렸다. 결과적으로 해상도는
|
||||
충분했고, **끊김 자체가 없었다.**
|
||||
|
||||
새 연결 **8856건 전부 200**. p95 는 평시 205.7ms 대 직후 204.3ms.
|
||||
|
||||
```
|
||||
08:58:40 845KB 요청 시작 (20k/s)
|
||||
08:58:52 ← nginx -s reload. 전송 12초째, 한가운데
|
||||
08:59:21 코드=200 바이트=845361(전량) 연결수=1
|
||||
```
|
||||
|
||||
연결수가 1이라는 것이 핵심이다 — 끊겨서 다시 붙은 것이 아니라, **옛 워커가
|
||||
그 요청을 끝까지 책임졌다.**
|
||||
|
||||
### 곁다리 — 측정 장치가 거짓말할 뻔했다
|
||||
|
||||
in-flight 감시에서 76건이 실패했다. 그대로 적었으면 "갱신 중 대규모 요청
|
||||
실패"라는 오보가 됐을 것이다. 서버 탓이 아니었다.
|
||||
|
||||
| 근거 | 값 |
|
||||
|---|---|
|
||||
| 같은 순간 폴링 | 49건 **전부 200** |
|
||||
| 연결수 | **0** — TCP 연결 시도조차 못 했다 |
|
||||
| 소요 시간 | **50µs** — DNS 조회보다도 짧다 |
|
||||
| 재현 | **0/100** |
|
||||
|
||||
**대조군이 오보를 막았다.** 상세는
|
||||
[`08-inflight-artifact.txt`](evidence/d4-certificate-renewal/08-inflight-artifact.txt).
|
||||
|
||||
전체 판정은 [D-4 문서](experiment-d4-certificate-renewal.md) 와
|
||||
[`13-verdict.txt`](evidence/d4-certificate-renewal/13-verdict.txt).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
| **D-1** | 백업·복구 | `...d1-backup-restore` | **빈 데이터베이스가 `200` 을 냈다** |
|
||||
| **D-2** | 버전 업그레이드 | `...d2-version-upgrade` | **이미지를 되돌려도 스키마는 안 돌아온다** |
|
||||
| **D-3** | 비밀 관리 | `...d3-secret-management` | **RBAC 만 실제로 감춘다** |
|
||||
| **D-4** | 인증서 갱신 | `...d4-certificate-renewal` | 구성은 정상. **강제 갱신은 사람 손이 필요** |
|
||||
| **후속** | 미측정 항목 채우기 | `...followup-untested-items` | 정방향 업그레이드 무중단 · **롤백 불가는 조건부였다** · role 변경은 요청으로 반영 안 됨 |
|
||||
| **D-4** | 인증서 갱신 | `...d4-certificate-renewal` | **갱신은 됐는데 36분 39초 반영 안 됨** (훅 3경로 전부 비었음). reload 자체는 **무중단**(8856건 0실패) |
|
||||
| **후속** | 미측정 3항목 채우기 | `...followup-untested-items` | **셋 다 완료.** 정방향 업그레이드 무중단 · **롤백 불가는 조건부였다** · role 변경은 요청으로 반영 안 됨 · **D-4 갱신 36분 39초 미반영** |
|
||||
|
||||
## 시각 자료
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
| A-6 | `tc ... dev eth0` | 인터페이스가 `enp1s0` 이다 |
|
||||
| A-6 | `enp1s0` 에 파드 IP 필터 | VXLAN 캡슐화로 **안 보인다** |
|
||||
| B-2 | `spring.sql.init` 스키마 | PostgreSQL 에 없는 `blob` 타입 + `continue-on-error` |
|
||||
| B-7·D-4 | `sudo nginx -T` 등 | **호스트 sudo 가 비밀번호를 요구**한다 |
|
||||
| B-7·D-4 | `sudo nginx -T` 등 | **호스트 sudo 가 비밀번호를 요구**한다. D-4 는 사용자가 직접 실행해 해소했다 |
|
||||
|
||||
**그래서 실험마다 "주입 성공 신호" 를 먼저 정하게 됐다** —
|
||||
`cluster_size` 하락, `not properly shut down` 로그, iptables 패킷 카운터,
|
||||
|
||||
Reference in New Issue
Block a user