[{"data":1,"prerenderedAt":1721},["ShallowReactive",2],{"post-\u002Fblog\u002Fassumerole-chaining-one-hour-ceiling":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"author":11,"tags":12,"body":17,"_type":1715,"_id":1716,"_source":1717,"_file":1718,"_stem":1719,"_extension":1720},"\u002Fblog\u002Fassumerole-chaining-one-hour-ceiling","blog",false,"","Chained AssumeRole sessions stop at one hour, silently","A role that assumes another role gets 3600 seconds, whatever its MaxSessionDuration allows. The exact error, and the batch job that dies at minute 61.","2026-11-02","Clement Baranger",[13,14,15,16],"s3","iam","sts","aws",{"type":18,"children":19,"toc":1706},"root",[20,37,42,49,105,111,132,165,222,231,236,271,299,305,310,319,327,332,337,441,446,454,492,565,582,607,632,638,646,832,837,845,1179,1184,1194,1204,1212,1336,1341,1358,1364,1408,1414,1536,1542,1695,1700],{"type":21,"tag":22,"props":23,"children":24},"element","p",{},[25,28,35],{"type":26,"value":27},"text","A nightly job ran for three weeks, then stopped at 01:00:03 with ",{"type":21,"tag":29,"props":30,"children":32},"code",{"className":31},[],[33],{"type":26,"value":34},"400 Bad Request",{"type":26,"value":36},". The error named a token — not a bucket, not a policy. Nothing had been deployed; the only change was the size of the dataset, from fifty minutes of work to seventy.",{"type":21,"tag":22,"props":38,"children":39},{},[40],{"type":26,"value":41},"The credentials had an expiry printed on them, and nobody had read it.",{"type":21,"tag":43,"props":44,"children":46},"h2",{"id":45},"the-short-version",[47],{"type":26,"value":48},"The short version",{"type":21,"tag":50,"props":51,"children":52},"ul",{},[53,59,72,85],{"type":21,"tag":54,"props":55,"children":56},"li",{},[57],{"type":26,"value":58},"Software does not log into S3 with a password. It gets a short-lived pass — an access key, a secret, and a session token — with an expiry written inside. Every request carries it.",{"type":21,"tag":54,"props":60,"children":61},{},[62,64,70],{"type":26,"value":63},"A role can use its own pass to fetch another role's pass. That second pass is capped at ",{"type":21,"tag":65,"props":66,"children":67},"strong",{},[68],{"type":26,"value":69},"3600 seconds by AWS STS",{"type":26,"value":71},", whatever the maximum session duration of either role says. It is the one place in IAM where a role's own setting stops applying.",{"type":21,"tag":54,"props":73,"children":74},{},[75,77,83],{"type":26,"value":76},"Ask for longer and the call fails immediately with a ",{"type":21,"tag":29,"props":78,"children":80},{"className":79},[],[81],{"type":26,"value":82},"ValidationError",{"type":26,"value":84},". Ask for nothing and you get 3600 seconds without warning — which is how a forty-minute staging run turns into a four-hour production job that dies at the hour mark.",{"type":21,"tag":54,"props":86,"children":87},{},[88,90,96,98,103],{"type":26,"value":89},"The failure is not retryable: S3 answers ",{"type":21,"tag":29,"props":91,"children":93},{"className":92},[],[94],{"type":26,"value":95},"400 ExpiredToken",{"type":26,"value":97},", and every part already uploaded to an unfinished multipart upload keeps billing at ",{"type":21,"tag":65,"props":99,"children":100},{},[101],{"type":26,"value":102},"$0.023\u002FGB-month",{"type":26,"value":104}," until something aborts it.",{"type":21,"tag":43,"props":106,"children":108},{"id":107},"what-actually-happens",[109],{"type":26,"value":110},"What actually happens",{"type":21,"tag":22,"props":112,"children":113},{},[114,116,122,124,130],{"type":26,"value":115},"When a program needs S3 access it calls ",{"type":21,"tag":29,"props":117,"children":119},{"className":118},[],[120],{"type":26,"value":121},"sts:AssumeRole",{"type":26,"value":123}," and receives three strings plus an ",{"type":21,"tag":29,"props":125,"children":127},{"className":126},[],[128],{"type":26,"value":129},"Expiration",{"type":26,"value":131}," timestamp. The three strings are handed to the SDK; the timestamp is usually thrown away. That timestamp is the whole subject of this article.",{"type":21,"tag":22,"props":133,"children":134},{},[135,141,143,148,150,155,157,163],{"type":21,"tag":29,"props":136,"children":138},{"className":137},[],[139],{"type":26,"value":140},"DurationSeconds",{"type":26,"value":142}," takes a value from ",{"type":21,"tag":65,"props":144,"children":145},{},[146],{"type":26,"value":147},"900 to 43 200",{"type":26,"value":149}," seconds, defaults to ",{"type":21,"tag":65,"props":151,"children":152},{},[153],{"type":26,"value":154},"3600",{"type":26,"value":156},", and cannot exceed the role's ",{"type":21,"tag":29,"props":158,"children":160},{"className":159},[],[161],{"type":26,"value":162},"MaxSessionDuration",{"type":26,"value":164}," — a per-role setting that can be raised from one hour to twelve, and that defaults to one hour when the role is created. So far, everything is configurable.",{"type":21,"tag":22,"props":166,"children":167},{},[168,170,176,178,184,186,191,193,198,200,206,208,213,215,220],{"type":26,"value":169},"The hop is what breaks it. A user with a long-term access key assumes ",{"type":21,"tag":29,"props":171,"children":173},{"className":172},[],[174],{"type":26,"value":175},"RoleA",{"type":26,"value":177}," — the ",{"type":21,"tag":179,"props":180,"children":181},"em",{},[182],{"type":26,"value":183},"initial",{"type":26,"value":185}," assumption, where ",{"type":21,"tag":29,"props":187,"children":189},{"className":188},[],[190],{"type":26,"value":175},{"type":26,"value":192},"'s own maximum applies. Then ",{"type":21,"tag":29,"props":194,"children":196},{"className":195},[],[197],{"type":26,"value":175},{"type":26,"value":199},"'s session token assumes ",{"type":21,"tag":29,"props":201,"children":203},{"className":202},[],[204],{"type":26,"value":205},"RoleB",{"type":26,"value":207},". That is ",{"type":21,"tag":65,"props":209,"children":210},{},[211],{"type":26,"value":212},"role chaining",{"type":26,"value":214},", and AWS states the rule plainly: chaining limits the role session to a maximum of one hour, ",{"type":21,"tag":179,"props":216,"children":217},{},[218],{"type":26,"value":219},"regardless of the maximum session duration configured for individual roles",{"type":26,"value":221},". Ask for more on that second call and the operation fails.",{"type":21,"tag":22,"props":223,"children":224},{},[225],{"type":21,"tag":226,"props":227,"children":230},"img",{"alt":228,"src":229},"A three-step ladder shows an IAM user assuming RoleA with DurationSeconds 43200 accepted, then the RoleA session assuming RoleB where 43200 is refused and 3600 granted; a side panel compares the ceilings for a user, a role and service-held compute credentials, and a timeline shows a six-hour job dying at the one-hour mark with 400 ExpiredToken","\u002Fdiagrams\u002Fassumerole-chaining-one-hour-ceiling.svg",[],{"type":21,"tag":22,"props":232,"children":233},{},[234],{"type":26,"value":235},"Two consequences follow, and only one is loud. The loud one: you request twelve hours on a chained call, it fails at the moment it is made, and the job never starts — annoying, easy to find.",{"type":21,"tag":22,"props":237,"children":238},{},[239,241,246,248,254,256,262,264,269],{"type":26,"value":240},"The quiet one: you request nothing. ",{"type":21,"tag":29,"props":242,"children":244},{"className":243},[],[245],{"type":26,"value":140},{"type":26,"value":247}," is optional, so ",{"type":21,"tag":29,"props":249,"children":251},{"className":250},[],[252],{"type":26,"value":253},"AssumeRole",{"type":26,"value":255}," returns 3600 seconds, the job starts, and it runs until minute 60. Nothing in the response, the ARN or the logs says \"this is a chained session\" — the ARN has the same shape at any depth, ",{"type":21,"tag":29,"props":257,"children":259},{"className":258},[],[260],{"type":26,"value":261},"arn:aws:sts::123456789012:assumed-role\u002FRoleB\u002Fbatch-20261102",{"type":26,"value":263},". The only observable difference is the ",{"type":21,"tag":29,"props":265,"children":267},{"className":266},[],[268],{"type":26,"value":129},{"type":26,"value":270}," value, and comparing it with the work is the only way to know.",{"type":21,"tag":22,"props":272,"children":273},{},[274,276,282,284,290,292,297],{"type":26,"value":275},"Three properties matter when planning around it. A chained session cannot call ",{"type":21,"tag":29,"props":277,"children":279},{"className":278},[],[280],{"type":26,"value":281},"GetSessionToken",{"type":26,"value":283}," or ",{"type":21,"tag":29,"props":285,"children":287},{"className":286},[],[288],{"type":26,"value":289},"GetFederationToken",{"type":26,"value":291},", so an MFA session must be minted before the first hop. Session tags survive only when declared transitive. And compute-held credentials on EC2, ECS, EKS and Lambda are ",{"type":21,"tag":65,"props":293,"children":294},{},[295],{"type":26,"value":296},"not",{"type":26,"value":298}," subject to the role's maximum session duration — the platform refreshes them, which is why the same code works in a container and fails on a laptop.",{"type":21,"tag":43,"props":300,"children":302},{"id":301},"where-it-bites",[303],{"type":26,"value":304},"Where it bites",{"type":21,"tag":22,"props":306,"children":307},{},[308],{"type":26,"value":309},"The two ways to be told no, and they are different strings:",{"type":21,"tag":311,"props":312,"children":314},"pre",{"code":313},"An error occurred (ValidationError) when calling the AssumeRole operation:\nThe requested DurationSeconds exceeds the MaxSessionDuration set for this role.\n",[315],{"type":21,"tag":29,"props":316,"children":317},{"__ignoreMap":7},[318],{"type":26,"value":313},{"type":21,"tag":311,"props":320,"children":322},{"code":321},"An error occurred (ValidationError) when calling the AssumeRole operation:\nThe requested DurationSeconds exceeds the 1 hour session limit for roles assumed by role chaining.\n",[323],{"type":21,"tag":29,"props":324,"children":325},{"__ignoreMap":7},[326],{"type":26,"value":321},{"type":21,"tag":22,"props":328,"children":329},{},[330],{"type":26,"value":331},"The first is fixable by raising a setting. The second is not: no setting, no support case, no policy grants more than 3600 seconds on a chained assumption. Incidentally, the chained-session string never appears in a CloudTrail event — only in the caller's stderr.",{"type":21,"tag":22,"props":333,"children":334},{},[335],{"type":26,"value":336},"Where the ceiling comes from, by caller:",{"type":21,"tag":338,"props":339,"children":340},"table",{},[341,365],{"type":21,"tag":342,"props":343,"children":344},"thead",{},[345],{"type":21,"tag":346,"props":347,"children":348},"tr",{},[349,355,360],{"type":21,"tag":350,"props":351,"children":352},"th",{},[353],{"type":26,"value":354},"Caller",{"type":21,"tag":350,"props":356,"children":357},{},[358],{"type":26,"value":359},"Ceiling",{"type":21,"tag":350,"props":361,"children":362},{},[363],{"type":26,"value":364},"Default",{"type":21,"tag":366,"props":367,"children":368},"tbody",{},[369,399,423],{"type":21,"tag":346,"props":370,"children":371},{},[372,383,395],{"type":21,"tag":373,"props":374,"children":375},"td",{},[376,378],{"type":26,"value":377},"IAM user long-term key → ",{"type":21,"tag":29,"props":379,"children":381},{"className":380},[],[382],{"type":26,"value":253},{"type":21,"tag":373,"props":384,"children":385},{},[386,388,393],{"type":26,"value":387},"role's ",{"type":21,"tag":29,"props":389,"children":391},{"className":390},[],[392],{"type":26,"value":162},{"type":26,"value":394}," (3600–43 200)",{"type":21,"tag":373,"props":396,"children":397},{},[398],{"type":26,"value":154},{"type":21,"tag":346,"props":400,"children":401},{},[402,414,419],{"type":21,"tag":373,"props":403,"children":404},{},[405,407,412],{"type":26,"value":406},"Temporary credentials → ",{"type":21,"tag":29,"props":408,"children":410},{"className":409},[],[411],{"type":26,"value":253},{"type":26,"value":413}," (chaining)",{"type":21,"tag":373,"props":415,"children":416},{},[417],{"type":26,"value":418},"3600 s, hard",{"type":21,"tag":373,"props":420,"children":421},{},[422],{"type":26,"value":154},{"type":21,"tag":346,"props":424,"children":425},{},[426,431,436],{"type":21,"tag":373,"props":427,"children":428},{},[429],{"type":26,"value":430},"Code on EC2 \u002F ECS \u002F EKS \u002F Lambda",{"type":21,"tag":373,"props":432,"children":433},{},[434],{"type":26,"value":435},"platform-managed, refreshed",{"type":21,"tag":373,"props":437,"children":438},{},[439],{"type":26,"value":440},"not the role setting",{"type":21,"tag":22,"props":442,"children":443},{},[444],{"type":26,"value":445},"The runtime failure looks like this, and it arrives in the middle of a run rather than at the start:",{"type":21,"tag":311,"props":447,"children":449},{"code":448},"An error occurred (ExpiredToken) when calling the ListObjectsV2 operation:\nThe provided token has expired.\n",[450],{"type":21,"tag":29,"props":451,"children":452},{"__ignoreMap":7},[453],{"type":26,"value":448},{"type":21,"tag":22,"props":455,"children":456},{},[457,459,465,467,473,475,481,483,490],{"type":26,"value":458},"That is the S3 code ",{"type":21,"tag":29,"props":460,"children":462},{"className":461},[],[463],{"type":26,"value":464},"ExpiredToken",{"type":26,"value":466},", HTTP ",{"type":21,"tag":29,"props":468,"children":470},{"className":469},[],[471],{"type":26,"value":472},"400",{"type":26,"value":474},", message ",{"type":21,"tag":29,"props":476,"children":478},{"className":477},[],[479],{"type":26,"value":480},"The provided token has expired.",{"type":26,"value":482}," It is a client error, so the SDK's default retry policy — throttling and server errors — does not retry it. A wrapper that retries three times burns three attempts in a second and reports a permission problem, sending whoever is on call to the bucket policy instead of the clock. ",{"type":21,"tag":484,"props":485,"children":487},"a",{"href":486},"\u002Fblog\u002Fbucket-policy-allow-still-denied",[488],{"type":26,"value":489},"The five-gate evaluation order",{"type":26,"value":491}," covers that investigation.",{"type":21,"tag":22,"props":493,"children":494},{},[495,500,502,508,510,516,518,524,526,532,534,540,542,548,550,556,558,563],{"type":21,"tag":65,"props":496,"children":497},{},[498],{"type":26,"value":499},"The shared-config trap.",{"type":26,"value":501}," Someone makes the chain permanent in ",{"type":21,"tag":29,"props":503,"children":505},{"className":504},[],[506],{"type":26,"value":507},"~\u002F.aws\u002Fconfig",{"type":26,"value":509},": a ",{"type":21,"tag":29,"props":511,"children":513},{"className":512},[],[514],{"type":26,"value":515},"batch",{"type":26,"value":517}," profile whose ",{"type":21,"tag":29,"props":519,"children":521},{"className":520},[],[522],{"type":26,"value":523},"source_profile",{"type":26,"value":525}," is ",{"type":21,"tag":29,"props":527,"children":529},{"className":528},[],[530],{"type":26,"value":531},"platform-admin",{"type":26,"value":533},", which itself assumes from a ",{"type":21,"tag":29,"props":535,"children":537},{"className":536},[],[538],{"type":26,"value":539},"base",{"type":26,"value":541}," profile. Every ",{"type":21,"tag":29,"props":543,"children":545},{"className":544},[],[546],{"type":26,"value":547},"--profile batch",{"type":26,"value":549}," call is now a chained assumption, and the ",{"type":21,"tag":29,"props":551,"children":553},{"className":552},[],[554],{"type":26,"value":555},"duration_seconds = 43200",{"type":26,"value":557}," in that block fails on the first call. It worked while ",{"type":21,"tag":29,"props":559,"children":561},{"className":560},[],[562],{"type":26,"value":523},{"type":26,"value":564}," pointed at an IAM user. Nobody edited the role.",{"type":21,"tag":22,"props":566,"children":567},{},[568,573,575,580],{"type":21,"tag":65,"props":569,"children":570},{},[571],{"type":26,"value":572},"The refresh trap.",{"type":26,"value":574}," A credential process that re-assumes the role looks like the fix — as long as the parent session lives, because the refresh call is signed with the parent's token. Once that expires, every refresh returns ",{"type":21,"tag":29,"props":576,"children":578},{"className":577},[],[579],{"type":26,"value":464},{"type":26,"value":581}," and child sessions stop renewing. Two clocks, and chaining means you own both.",{"type":21,"tag":22,"props":583,"children":584},{},[585,590,592,598,600,605],{"type":21,"tag":65,"props":586,"children":587},{},[588],{"type":26,"value":589},"The tail nobody invoices.",{"type":26,"value":591}," A four-hour copy that dies at hour one leaves an open multipart upload, and S3 bills its parts as storage until the upload is completed or aborted. A worked example: 250 GB left behind on S3 Standard in ",{"type":21,"tag":29,"props":593,"children":595},{"className":594},[],[596],{"type":26,"value":597},"us-east-1",{"type":26,"value":599}," costs 250 × $0.023 = ",{"type":21,"tag":65,"props":601,"children":602},{},[603],{"type":26,"value":604},"$5.75 per month",{"type":26,"value":606},", indefinitely, for a job that produced nothing. Multiply by every retry.",{"type":21,"tag":22,"props":608,"children":609},{},[610,615,617,622,624,630],{"type":21,"tag":65,"props":611,"children":612},{},[613],{"type":26,"value":614},"It is an AWS STS rule, not an S3 rule.",{"type":26,"value":616}," MinIO's STS endpoint allows ",{"type":21,"tag":29,"props":618,"children":620},{"className":619},[],[621],{"type":26,"value":140},{"type":26,"value":623}," from 900 seconds to 365 days, default one hour, set through ",{"type":21,"tag":29,"props":625,"children":627},{"className":626},[],[628],{"type":26,"value":629},"MINIO_STS_DURATION",{"type":26,"value":631}," — a default, not a chain ceiling. A workload that assumes two roles for six hours against a local MinIO dies at the hour mark on AWS. Test the number against the endpoint you ship to.",{"type":21,"tag":43,"props":633,"children":635},{"id":634},"doing-it-right",[636],{"type":26,"value":637},"Doing it right",{"type":21,"tag":22,"props":639,"children":640},{},[641],{"type":21,"tag":65,"props":642,"children":643},{},[644],{"type":26,"value":645},"1. Read the expiry you were given, not the one you requested.",{"type":21,"tag":311,"props":647,"children":651},{"code":648,"language":649,"meta":7,"className":650,"style":7},"aws sts assume-role \\\n  --role-arn arn:aws:iam::123456789012:role\u002Fbatch-writer \\\n  --role-session-name batch-20261102 \\\n  --duration-seconds 3600 \\\n  --profile platform-admin \\\n  --output json > \u002Ftmp\u002Fcreds.json\n\njq -r '.Credentials.Expiration' \u002Ftmp\u002Fcreds.json\ndate -u +%FT%TZ\n","bash","language-bash shiki shiki-themes github-light-high-contrast github-dark-high-contrast",[652],{"type":21,"tag":29,"props":653,"children":654},{"__ignoreMap":7},[655,683,702,720,738,756,780,790,813],{"type":21,"tag":656,"props":657,"children":660},"span",{"class":658,"line":659},"line",1,[661,666,672,677],{"type":21,"tag":656,"props":662,"children":664},{"style":663},"--shiki-default:#702C00;--shiki-dark:#FFB757",[665],{"type":26,"value":16},{"type":21,"tag":656,"props":667,"children":669},{"style":668},"--shiki-default:#032563;--shiki-dark:#ADDCFF",[670],{"type":26,"value":671}," sts",{"type":21,"tag":656,"props":673,"children":674},{"style":668},[675],{"type":26,"value":676}," assume-role",{"type":21,"tag":656,"props":678,"children":680},{"style":679},"--shiki-default:#A0111F;--shiki-dark:#FF9492",[681],{"type":26,"value":682}," \\\n",{"type":21,"tag":656,"props":684,"children":686},{"class":658,"line":685},2,[687,693,698],{"type":21,"tag":656,"props":688,"children":690},{"style":689},"--shiki-default:#023B95;--shiki-dark:#91CBFF",[691],{"type":26,"value":692},"  --role-arn",{"type":21,"tag":656,"props":694,"children":695},{"style":668},[696],{"type":26,"value":697}," arn:aws:iam::123456789012:role\u002Fbatch-writer",{"type":21,"tag":656,"props":699,"children":700},{"style":679},[701],{"type":26,"value":682},{"type":21,"tag":656,"props":703,"children":705},{"class":658,"line":704},3,[706,711,716],{"type":21,"tag":656,"props":707,"children":708},{"style":689},[709],{"type":26,"value":710},"  --role-session-name",{"type":21,"tag":656,"props":712,"children":713},{"style":668},[714],{"type":26,"value":715}," batch-20261102",{"type":21,"tag":656,"props":717,"children":718},{"style":679},[719],{"type":26,"value":682},{"type":21,"tag":656,"props":721,"children":723},{"class":658,"line":722},4,[724,729,734],{"type":21,"tag":656,"props":725,"children":726},{"style":689},[727],{"type":26,"value":728},"  --duration-seconds",{"type":21,"tag":656,"props":730,"children":731},{"style":689},[732],{"type":26,"value":733}," 3600",{"type":21,"tag":656,"props":735,"children":736},{"style":679},[737],{"type":26,"value":682},{"type":21,"tag":656,"props":739,"children":741},{"class":658,"line":740},5,[742,747,752],{"type":21,"tag":656,"props":743,"children":744},{"style":689},[745],{"type":26,"value":746},"  --profile",{"type":21,"tag":656,"props":748,"children":749},{"style":668},[750],{"type":26,"value":751}," platform-admin",{"type":21,"tag":656,"props":753,"children":754},{"style":679},[755],{"type":26,"value":682},{"type":21,"tag":656,"props":757,"children":759},{"class":658,"line":758},6,[760,765,770,775],{"type":21,"tag":656,"props":761,"children":762},{"style":689},[763],{"type":26,"value":764},"  --output",{"type":21,"tag":656,"props":766,"children":767},{"style":668},[768],{"type":26,"value":769}," json",{"type":21,"tag":656,"props":771,"children":772},{"style":679},[773],{"type":26,"value":774}," >",{"type":21,"tag":656,"props":776,"children":777},{"style":668},[778],{"type":26,"value":779}," \u002Ftmp\u002Fcreds.json\n",{"type":21,"tag":656,"props":781,"children":783},{"class":658,"line":782},7,[784],{"type":21,"tag":656,"props":785,"children":787},{"emptyLinePlaceholder":786},true,[788],{"type":26,"value":789},"\n",{"type":21,"tag":656,"props":791,"children":793},{"class":658,"line":792},8,[794,799,804,809],{"type":21,"tag":656,"props":795,"children":796},{"style":663},[797],{"type":26,"value":798},"jq",{"type":21,"tag":656,"props":800,"children":801},{"style":689},[802],{"type":26,"value":803}," -r",{"type":21,"tag":656,"props":805,"children":806},{"style":668},[807],{"type":26,"value":808}," '.Credentials.Expiration'",{"type":21,"tag":656,"props":810,"children":811},{"style":668},[812],{"type":26,"value":779},{"type":21,"tag":656,"props":814,"children":816},{"class":658,"line":815},9,[817,822,827],{"type":21,"tag":656,"props":818,"children":819},{"style":663},[820],{"type":26,"value":821},"date",{"type":21,"tag":656,"props":823,"children":824},{"style":689},[825],{"type":26,"value":826}," -u",{"type":21,"tag":656,"props":828,"children":829},{"style":668},[830],{"type":26,"value":831}," +%FT%TZ\n",{"type":21,"tag":22,"props":833,"children":834},{},[835],{"type":26,"value":836},"Two timestamps an hour apart against a four-hour job is the bug, found before it happens. Run this from the profile the job actually uses, not from your admin profile.",{"type":21,"tag":22,"props":838,"children":839},{},[840],{"type":21,"tag":65,"props":841,"children":842},{},[843],{"type":26,"value":844},"2. Make the job refuse to start when the session is too short.",{"type":21,"tag":311,"props":846,"children":850},{"code":847,"language":848,"meta":7,"className":849,"style":7},"import datetime as dt, json\n\ncreds = json.load(open(\"\u002Ftmp\u002Fcreds.json\"))[\"Credentials\"]\nexpires = dt.datetime.fromisoformat(creds[\"Expiration\"].replace(\"Z\", \"+00:00\"))\nneeded = dt.timedelta(hours=4)                 # measured, not guessed\nnow = dt.datetime.now(dt.timezone.utc)\n\nif expires - now \u003C needed:\n    raise SystemExit(f\"session ends {expires:%H:%M:%SZ}, job needs {needed}\")\n","python","language-python shiki shiki-themes github-light-high-contrast github-dark-high-contrast",[851],{"type":21,"tag":29,"props":852,"children":853},{"__ignoreMap":7},[854,878,885,933,980,1022,1039,1046,1079],{"type":21,"tag":656,"props":855,"children":856},{"class":658,"line":659},[857,862,868,873],{"type":21,"tag":656,"props":858,"children":859},{"style":679},[860],{"type":26,"value":861},"import",{"type":21,"tag":656,"props":863,"children":865},{"style":864},"--shiki-default:#0E1116;--shiki-dark:#F0F3F6",[866],{"type":26,"value":867}," datetime ",{"type":21,"tag":656,"props":869,"children":870},{"style":679},[871],{"type":26,"value":872},"as",{"type":21,"tag":656,"props":874,"children":875},{"style":864},[876],{"type":26,"value":877}," dt, json\n",{"type":21,"tag":656,"props":879,"children":880},{"class":658,"line":685},[881],{"type":21,"tag":656,"props":882,"children":883},{"emptyLinePlaceholder":786},[884],{"type":26,"value":789},{"type":21,"tag":656,"props":886,"children":887},{"class":658,"line":704},[888,893,898,903,908,913,918,923,928],{"type":21,"tag":656,"props":889,"children":890},{"style":864},[891],{"type":26,"value":892},"creds ",{"type":21,"tag":656,"props":894,"children":895},{"style":679},[896],{"type":26,"value":897},"=",{"type":21,"tag":656,"props":899,"children":900},{"style":864},[901],{"type":26,"value":902}," json.load(",{"type":21,"tag":656,"props":904,"children":905},{"style":689},[906],{"type":26,"value":907},"open",{"type":21,"tag":656,"props":909,"children":910},{"style":864},[911],{"type":26,"value":912},"(",{"type":21,"tag":656,"props":914,"children":915},{"style":668},[916],{"type":26,"value":917},"\"\u002Ftmp\u002Fcreds.json\"",{"type":21,"tag":656,"props":919,"children":920},{"style":864},[921],{"type":26,"value":922},"))[",{"type":21,"tag":656,"props":924,"children":925},{"style":668},[926],{"type":26,"value":927},"\"Credentials\"",{"type":21,"tag":656,"props":929,"children":930},{"style":864},[931],{"type":26,"value":932},"]\n",{"type":21,"tag":656,"props":934,"children":935},{"class":658,"line":722},[936,941,945,950,955,960,965,970,975],{"type":21,"tag":656,"props":937,"children":938},{"style":864},[939],{"type":26,"value":940},"expires ",{"type":21,"tag":656,"props":942,"children":943},{"style":679},[944],{"type":26,"value":897},{"type":21,"tag":656,"props":946,"children":947},{"style":864},[948],{"type":26,"value":949}," dt.datetime.fromisoformat(creds[",{"type":21,"tag":656,"props":951,"children":952},{"style":668},[953],{"type":26,"value":954},"\"Expiration\"",{"type":21,"tag":656,"props":956,"children":957},{"style":864},[958],{"type":26,"value":959},"].replace(",{"type":21,"tag":656,"props":961,"children":962},{"style":668},[963],{"type":26,"value":964},"\"Z\"",{"type":21,"tag":656,"props":966,"children":967},{"style":864},[968],{"type":26,"value":969},", ",{"type":21,"tag":656,"props":971,"children":972},{"style":668},[973],{"type":26,"value":974},"\"+00:00\"",{"type":21,"tag":656,"props":976,"children":977},{"style":864},[978],{"type":26,"value":979},"))\n",{"type":21,"tag":656,"props":981,"children":982},{"class":658,"line":740},[983,988,992,997,1002,1006,1011,1016],{"type":21,"tag":656,"props":984,"children":985},{"style":864},[986],{"type":26,"value":987},"needed ",{"type":21,"tag":656,"props":989,"children":990},{"style":679},[991],{"type":26,"value":897},{"type":21,"tag":656,"props":993,"children":994},{"style":864},[995],{"type":26,"value":996}," dt.timedelta(",{"type":21,"tag":656,"props":998,"children":999},{"style":663},[1000],{"type":26,"value":1001},"hours",{"type":21,"tag":656,"props":1003,"children":1004},{"style":679},[1005],{"type":26,"value":897},{"type":21,"tag":656,"props":1007,"children":1008},{"style":689},[1009],{"type":26,"value":1010},"4",{"type":21,"tag":656,"props":1012,"children":1013},{"style":864},[1014],{"type":26,"value":1015},")                 ",{"type":21,"tag":656,"props":1017,"children":1019},{"style":1018},"--shiki-default:#66707B;--shiki-dark:#BDC4CC",[1020],{"type":26,"value":1021},"# measured, not guessed\n",{"type":21,"tag":656,"props":1023,"children":1024},{"class":658,"line":758},[1025,1030,1034],{"type":21,"tag":656,"props":1026,"children":1027},{"style":864},[1028],{"type":26,"value":1029},"now ",{"type":21,"tag":656,"props":1031,"children":1032},{"style":679},[1033],{"type":26,"value":897},{"type":21,"tag":656,"props":1035,"children":1036},{"style":864},[1037],{"type":26,"value":1038}," dt.datetime.now(dt.timezone.utc)\n",{"type":21,"tag":656,"props":1040,"children":1041},{"class":658,"line":782},[1042],{"type":21,"tag":656,"props":1043,"children":1044},{"emptyLinePlaceholder":786},[1045],{"type":26,"value":789},{"type":21,"tag":656,"props":1047,"children":1048},{"class":658,"line":792},[1049,1054,1059,1064,1069,1074],{"type":21,"tag":656,"props":1050,"children":1051},{"style":679},[1052],{"type":26,"value":1053},"if",{"type":21,"tag":656,"props":1055,"children":1056},{"style":864},[1057],{"type":26,"value":1058}," expires ",{"type":21,"tag":656,"props":1060,"children":1061},{"style":679},[1062],{"type":26,"value":1063},"-",{"type":21,"tag":656,"props":1065,"children":1066},{"style":864},[1067],{"type":26,"value":1068}," now ",{"type":21,"tag":656,"props":1070,"children":1071},{"style":679},[1072],{"type":26,"value":1073},"\u003C",{"type":21,"tag":656,"props":1075,"children":1076},{"style":864},[1077],{"type":26,"value":1078}," needed:\n",{"type":21,"tag":656,"props":1080,"children":1081},{"class":658,"line":815},[1082,1087,1092,1096,1101,1106,1111,1116,1121,1126,1131,1136,1141,1145,1150,1155,1159,1164,1169,1174],{"type":21,"tag":656,"props":1083,"children":1084},{"style":679},[1085],{"type":26,"value":1086},"    raise",{"type":21,"tag":656,"props":1088,"children":1089},{"style":689},[1090],{"type":26,"value":1091}," SystemExit",{"type":21,"tag":656,"props":1093,"children":1094},{"style":864},[1095],{"type":26,"value":912},{"type":21,"tag":656,"props":1097,"children":1098},{"style":679},[1099],{"type":26,"value":1100},"f",{"type":21,"tag":656,"props":1102,"children":1103},{"style":668},[1104],{"type":26,"value":1105},"\"session ends ",{"type":21,"tag":656,"props":1107,"children":1108},{"style":679},[1109],{"type":26,"value":1110},"{",{"type":21,"tag":656,"props":1112,"children":1113},{"style":864},[1114],{"type":26,"value":1115},"expires",{"type":21,"tag":656,"props":1117,"children":1118},{"style":679},[1119],{"type":26,"value":1120},":",{"type":21,"tag":656,"props":1122,"children":1123},{"style":864},[1124],{"type":26,"value":1125},"%",{"type":21,"tag":656,"props":1127,"children":1128},{"style":679},[1129],{"type":26,"value":1130},"H",{"type":21,"tag":656,"props":1132,"children":1133},{"style":864},[1134],{"type":26,"value":1135},":%",{"type":21,"tag":656,"props":1137,"children":1138},{"style":679},[1139],{"type":26,"value":1140},"M",{"type":21,"tag":656,"props":1142,"children":1143},{"style":864},[1144],{"type":26,"value":1135},{"type":21,"tag":656,"props":1146,"children":1147},{"style":679},[1148],{"type":26,"value":1149},"SZ}",{"type":21,"tag":656,"props":1151,"children":1152},{"style":668},[1153],{"type":26,"value":1154},", job needs ",{"type":21,"tag":656,"props":1156,"children":1157},{"style":679},[1158],{"type":26,"value":1110},{"type":21,"tag":656,"props":1160,"children":1161},{"style":864},[1162],{"type":26,"value":1163},"needed",{"type":21,"tag":656,"props":1165,"children":1166},{"style":679},[1167],{"type":26,"value":1168},"}",{"type":21,"tag":656,"props":1170,"children":1171},{"style":668},[1172],{"type":26,"value":1173},"\"",{"type":21,"tag":656,"props":1175,"children":1176},{"style":864},[1177],{"type":26,"value":1178},")\n",{"type":21,"tag":22,"props":1180,"children":1181},{},[1182],{"type":26,"value":1183},"A job that exits in two seconds with a clear reason is a monitoring event. A job that exits after sixty minutes is an incident.",{"type":21,"tag":22,"props":1185,"children":1186},{},[1187,1192],{"type":21,"tag":65,"props":1188,"children":1189},{},[1190],{"type":26,"value":1191},"3. Remove the hop where the permissions allow it.",{"type":26,"value":1193}," One role carrying the union of what the two did is simpler, and keeps a twelve-hour maximum available. Where the split exists for a reason, federate straight into the target role — OIDC or SAML issues the session directly, so the first assumption is also the last.",{"type":21,"tag":22,"props":1195,"children":1196},{},[1197,1202],{"type":21,"tag":65,"props":1198,"children":1199},{},[1200],{"type":26,"value":1201},"4. If the hop stays, cut the work into sub-hour chunks.",{"type":26,"value":1203}," Checkpoint by key prefix or object list, re-assume per chunk, and make each chunk idempotent so a re-run overwrites rather than duplicates. Or move the long leg onto compute whose credentials the platform refreshes — an instance profile, a task role, a pod identity.",{"type":21,"tag":22,"props":1205,"children":1206},{},[1207],{"type":21,"tag":65,"props":1208,"children":1209},{},[1210],{"type":26,"value":1211},"5. Abort the leftovers, so a failed run stops costing money.",{"type":21,"tag":311,"props":1213,"children":1215},{"code":1214,"language":649,"meta":7,"className":650,"style":7},"cat > \u002Ftmp\u002Fabort-mpu.json \u003C\u003C'JSON'\n{ \"Rules\": [ { \"ID\": \"AbortStaleMultipart\", \"Status\": \"Enabled\",\n  \"Filter\": { \"Prefix\": \"\" },\n  \"AbortIncompleteMultipartUpload\": { \"DaysAfterInitiation\": 1 } } ] }\nJSON\n\naws s3api put-bucket-lifecycle-configuration \\\n  --bucket batch-output-prod \\\n  --lifecycle-configuration file:\u002F\u002F\u002Ftmp\u002Fabort-mpu.json\n",[1216],{"type":21,"tag":29,"props":1217,"children":1218},{"__ignoreMap":7},[1219,1246,1254,1262,1270,1278,1285,1306,1323],{"type":21,"tag":656,"props":1220,"children":1221},{"class":658,"line":659},[1222,1227,1231,1236,1241],{"type":21,"tag":656,"props":1223,"children":1224},{"style":663},[1225],{"type":26,"value":1226},"cat",{"type":21,"tag":656,"props":1228,"children":1229},{"style":679},[1230],{"type":26,"value":774},{"type":21,"tag":656,"props":1232,"children":1233},{"style":668},[1234],{"type":26,"value":1235}," \u002Ftmp\u002Fabort-mpu.json",{"type":21,"tag":656,"props":1237,"children":1238},{"style":679},[1239],{"type":26,"value":1240}," \u003C\u003C",{"type":21,"tag":656,"props":1242,"children":1243},{"style":864},[1244],{"type":26,"value":1245},"'JSON'\n",{"type":21,"tag":656,"props":1247,"children":1248},{"class":658,"line":685},[1249],{"type":21,"tag":656,"props":1250,"children":1251},{"style":668},[1252],{"type":26,"value":1253},"{ \"Rules\": [ { \"ID\": \"AbortStaleMultipart\", \"Status\": \"Enabled\",\n",{"type":21,"tag":656,"props":1255,"children":1256},{"class":658,"line":704},[1257],{"type":21,"tag":656,"props":1258,"children":1259},{"style":668},[1260],{"type":26,"value":1261},"  \"Filter\": { \"Prefix\": \"\" },\n",{"type":21,"tag":656,"props":1263,"children":1264},{"class":658,"line":722},[1265],{"type":21,"tag":656,"props":1266,"children":1267},{"style":668},[1268],{"type":26,"value":1269},"  \"AbortIncompleteMultipartUpload\": { \"DaysAfterInitiation\": 1 } } ] }\n",{"type":21,"tag":656,"props":1271,"children":1272},{"class":658,"line":740},[1273],{"type":21,"tag":656,"props":1274,"children":1275},{"style":864},[1276],{"type":26,"value":1277},"JSON\n",{"type":21,"tag":656,"props":1279,"children":1280},{"class":658,"line":758},[1281],{"type":21,"tag":656,"props":1282,"children":1283},{"emptyLinePlaceholder":786},[1284],{"type":26,"value":789},{"type":21,"tag":656,"props":1286,"children":1287},{"class":658,"line":782},[1288,1292,1297,1302],{"type":21,"tag":656,"props":1289,"children":1290},{"style":663},[1291],{"type":26,"value":16},{"type":21,"tag":656,"props":1293,"children":1294},{"style":668},[1295],{"type":26,"value":1296}," s3api",{"type":21,"tag":656,"props":1298,"children":1299},{"style":668},[1300],{"type":26,"value":1301}," put-bucket-lifecycle-configuration",{"type":21,"tag":656,"props":1303,"children":1304},{"style":679},[1305],{"type":26,"value":682},{"type":21,"tag":656,"props":1307,"children":1308},{"class":658,"line":792},[1309,1314,1319],{"type":21,"tag":656,"props":1310,"children":1311},{"style":689},[1312],{"type":26,"value":1313},"  --bucket",{"type":21,"tag":656,"props":1315,"children":1316},{"style":668},[1317],{"type":26,"value":1318}," batch-output-prod",{"type":21,"tag":656,"props":1320,"children":1321},{"style":679},[1322],{"type":26,"value":682},{"type":21,"tag":656,"props":1324,"children":1325},{"class":658,"line":815},[1326,1331],{"type":21,"tag":656,"props":1327,"children":1328},{"style":689},[1329],{"type":26,"value":1330},"  --lifecycle-configuration",{"type":21,"tag":656,"props":1332,"children":1333},{"style":668},[1334],{"type":26,"value":1335}," file:\u002F\u002F\u002Ftmp\u002Fabort-mpu.json\n",{"type":21,"tag":22,"props":1337,"children":1338},{},[1339],{"type":26,"value":1340},"One day is aggressive on purpose: an upload that legitimately spans a day is a design that will break at the hour mark anyway.",{"type":21,"tag":22,"props":1342,"children":1343},{},[1344,1349,1351,1356],{"type":21,"tag":65,"props":1345,"children":1346},{},[1347],{"type":26,"value":1348},"6. Alarm on the code, not on the status class.",{"type":26,"value":1350}," Count ",{"type":21,"tag":29,"props":1352,"children":1354},{"className":1353},[],[1355],{"type":26,"value":464},{"type":26,"value":1357}," separately from the rest of the 4xx responses. A single occurrence means a job is already dead, and the count will tell you how many of them died at the same minute — which is what a shared credential looks like.",{"type":21,"tag":43,"props":1359,"children":1361},{"id":1360},"how-s3-explorer-fits",[1362],{"type":26,"value":1363},"How S3 Explorer fits",{"type":21,"tag":22,"props":1365,"children":1366},{},[1367,1369,1374,1376,1381,1383,1389,1391,1396,1398,1406],{"type":26,"value":1368},"The credentials a long job receives are worth inspecting before the job runs, and S3 Explorer's ",{"type":21,"tag":65,"props":1370,"children":1371},{},[1372],{"type":26,"value":1373},"Test connection",{"type":26,"value":1375}," validates them and reports how many buckets they actually see before the profile is saved — a chained set that cannot list anything is caught in seconds rather than at 01:00. The ",{"type":21,"tag":65,"props":1377,"children":1378},{},[1379],{"type":26,"value":1380},"per-request metrics dashboard",{"type":26,"value":1382}," counts the session's calls by category with an error rate computed locally, so four thousand ",{"type":21,"tag":29,"props":1384,"children":1386},{"className":1385},[],[1387],{"type":26,"value":1388},"200",{"type":26,"value":1390},"s followed by a ",{"type":21,"tag":29,"props":1392,"children":1394},{"className":1393},[],[1395],{"type":26,"value":472},{"type":26,"value":1397}," reads as a change in the series instead of a line buried in a log. Multiple connection profiles let you sit on the parent role and the child role without leaving the window, and the Metadata and Versions tabs show which key and version a half-finished batch left behind. ",{"type":21,"tag":484,"props":1399,"children":1403},{"href":1400,"rel":1401},"https:\u002F\u002Fs3explorer.accessdevops.com",[1402],"nofollow",[1404],{"type":26,"value":1405},"S3 Explorer",{"type":26,"value":1407}," runs on Windows, macOS and Linux.",{"type":21,"tag":43,"props":1409,"children":1411},{"id":1410},"checklist",[1412],{"type":26,"value":1413},"Checklist",{"type":21,"tag":50,"props":1415,"children":1418},{"className":1416},[1417],"contains-task-list",[1419,1438,1461,1477,1486,1495,1511,1527],{"type":21,"tag":54,"props":1420,"children":1423},{"className":1421},[1422],"task-list-item",[1424,1429,1431,1436],{"type":21,"tag":1425,"props":1426,"children":1428},"input",{"disabled":786,"type":1427},"checkbox",[],{"type":26,"value":1430}," Every profile in ",{"type":21,"tag":29,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":26,"value":507},{"type":26,"value":1437}," has been traced: you know which ones chain.",{"type":21,"tag":54,"props":1439,"children":1441},{"className":1440},[1422],[1442,1445,1447,1452,1454,1459],{"type":21,"tag":1425,"props":1443,"children":1444},{"disabled":786,"type":1427},[],{"type":26,"value":1446}," Every ",{"type":21,"tag":29,"props":1448,"children":1450},{"className":1449},[],[1451],{"type":26,"value":253},{"type":26,"value":1453}," call passes ",{"type":21,"tag":29,"props":1455,"children":1457},{"className":1456},[],[1458],{"type":26,"value":140},{"type":26,"value":1460}," explicitly; nothing depends on the default.",{"type":21,"tag":54,"props":1462,"children":1464},{"className":1463},[1422],[1465,1468,1470,1475],{"type":21,"tag":1425,"props":1466,"children":1467},{"disabled":786,"type":1427},[],{"type":26,"value":1469}," Each job compares its measured runtime with the credential ",{"type":21,"tag":29,"props":1471,"children":1473},{"className":1472},[],[1474],{"type":26,"value":129},{"type":26,"value":1476}," before it starts work.",{"type":21,"tag":54,"props":1478,"children":1480},{"className":1479},[1422],[1481,1484],{"type":21,"tag":1425,"props":1482,"children":1483},{"disabled":786,"type":1427},[],{"type":26,"value":1485}," Work that genuinely needs more than an hour runs on compute whose credentials the platform refreshes.",{"type":21,"tag":54,"props":1487,"children":1489},{"className":1488},[1422],[1490,1493],{"type":21,"tag":1425,"props":1491,"children":1492},{"disabled":786,"type":1427},[],{"type":26,"value":1494}," A bucket lifecycle rule aborts incomplete multipart uploads within a day.",{"type":21,"tag":54,"props":1496,"children":1498},{"className":1497},[1422],[1499,1502,1504,1509],{"type":21,"tag":1425,"props":1500,"children":1501},{"disabled":786,"type":1427},[],{"type":26,"value":1503}," Alarms count ",{"type":21,"tag":29,"props":1505,"children":1507},{"className":1506},[],[1508],{"type":26,"value":464},{"type":26,"value":1510}," separately from other 4xx responses.",{"type":21,"tag":54,"props":1512,"children":1514},{"className":1513},[1422],[1515,1518,1520,1525],{"type":21,"tag":1425,"props":1516,"children":1517},{"disabled":786,"type":1427},[],{"type":26,"value":1519}," The runbook says \"re-assume\", not \"retry\": a ",{"type":21,"tag":29,"props":1521,"children":1523},{"className":1522},[],[1524],{"type":26,"value":472},{"type":26,"value":1526}," will not succeed on the second attempt.",{"type":21,"tag":54,"props":1528,"children":1530},{"className":1529},[1422],[1531,1534],{"type":21,"tag":1425,"props":1532,"children":1533},{"disabled":786,"type":1427},[],{"type":26,"value":1535}," A staging run has lasted longer than an hour before the production schedule was set.",{"type":21,"tag":43,"props":1537,"children":1539},{"id":1538},"sources",[1540],{"type":26,"value":1541},"Sources",{"type":21,"tag":50,"props":1543,"children":1544},{},[1545,1564,1576,1588,1606,1618,1637,1663,1675],{"type":21,"tag":54,"props":1546,"children":1547},{},[1548,1555,1557,1562],{"type":21,"tag":484,"props":1549,"children":1552},{"href":1550,"rel":1551},"https:\u002F\u002Fdocs.aws.amazon.com\u002FSTS\u002Flatest\u002FAPIReference\u002FAPI_AssumeRole.html",[1402],[1553],{"type":26,"value":1554},"AWS STS — AssumeRole",{"type":26,"value":1556},": ",{"type":21,"tag":29,"props":1558,"children":1560},{"className":1559},[],[1561],{"type":26,"value":140},{"type":26,"value":1563}," 900–43 200, default 3600, chaining limit.",{"type":21,"tag":54,"props":1565,"children":1566},{},[1567,1574],{"type":21,"tag":484,"props":1568,"children":1571},{"href":1569,"rel":1570},"https:\u002F\u002Fdocs.aws.amazon.com\u002FIAM\u002Flatest\u002FUserGuide\u002Fid_roles.html",[1402],[1572],{"type":26,"value":1573},"IAM — IAM roles",{"type":26,"value":1575},": role chaining applies regardless of the role's own maximum.",{"type":21,"tag":54,"props":1577,"children":1578},{},[1579,1586],{"type":21,"tag":484,"props":1580,"children":1583},{"href":1581,"rel":1582},"https:\u002F\u002Fdocs.aws.amazon.com\u002FIAM\u002Flatest\u002FUserGuide\u002Fid_roles_manage-assume.html",[1402],[1584],{"type":26,"value":1585},"IAM — Methods to assume a role",{"type":26,"value":1587},": lifetime per caller; compute credentials exempt.",{"type":21,"tag":54,"props":1589,"children":1590},{},[1591,1598,1599,1604],{"type":21,"tag":484,"props":1592,"children":1595},{"href":1593,"rel":1594},"https:\u002F\u002Fdocs.aws.amazon.com\u002FAmazonS3\u002Flatest\u002FAPI\u002FAPI_Error.html",[1402],[1596],{"type":26,"value":1597},"Amazon S3 — Error codes",{"type":26,"value":1556},{"type":21,"tag":29,"props":1600,"children":1602},{"className":1601},[],[1603],{"type":26,"value":464},{"type":26,"value":1605},", HTTP 400.",{"type":21,"tag":54,"props":1607,"children":1608},{},[1609,1616],{"type":21,"tag":484,"props":1610,"children":1613},{"href":1611,"rel":1612},"https:\u002F\u002Fdocs.aws.amazon.com\u002FAmazonS3\u002Flatest\u002Fuserguide\u002Fmpuoverview.html",[1402],[1614],{"type":26,"value":1615},"Amazon S3 — Multipart upload overview",{"type":26,"value":1617},": parts billed until completed or stopped.",{"type":21,"tag":54,"props":1619,"children":1620},{},[1621,1628,1630,1635],{"type":21,"tag":484,"props":1622,"children":1625},{"href":1623,"rel":1624},"https:\u002F\u002Faws.amazon.com\u002Fs3\u002Fpricing\u002F",[1402],[1626],{"type":26,"value":1627},"AWS S3 pricing",{"type":26,"value":1629},": $0.023\u002FGB-month, ",{"type":21,"tag":29,"props":1631,"children":1633},{"className":1632},[],[1634],{"type":26,"value":597},{"type":26,"value":1636},", checked 2 November 2026.",{"type":21,"tag":54,"props":1638,"children":1639},{},[1640,1647,1648,1654,1656,1661],{"type":21,"tag":484,"props":1641,"children":1644},{"href":1642,"rel":1643},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fcli\u002Flatest\u002Fuserguide\u002Fcli-configure-role.html",[1402],[1645],{"type":26,"value":1646},"AWS CLI — Using an IAM role",{"type":26,"value":1556},{"type":21,"tag":29,"props":1649,"children":1651},{"className":1650},[],[1652],{"type":26,"value":1653},"role_arn",{"type":26,"value":1655}," plus ",{"type":21,"tag":29,"props":1657,"children":1659},{"className":1658},[],[1660],{"type":26,"value":523},{"type":26,"value":1662},".",{"type":21,"tag":54,"props":1664,"children":1665},{},[1666,1673],{"type":21,"tag":484,"props":1667,"children":1670},{"href":1668,"rel":1669},"https:\u002F\u002Fdocs.min.io\u002Faistor\u002Freference\u002Faistor-server\u002Fsettings\u002Fiam\u002Fsts\u002F",[1402],[1671],{"type":26,"value":1672},"MinIO AIStor — STS settings",{"type":26,"value":1674},": default one hour, 15 minutes to 365 days.",{"type":21,"tag":54,"props":1676,"children":1677},{},[1678,1680,1685,1687,1694],{"type":26,"value":1679},"Chained-session ",{"type":21,"tag":29,"props":1681,"children":1683},{"className":1682},[],[1684],{"type":26,"value":82},{"type":26,"value":1686},", reproduced: ",{"type":21,"tag":484,"props":1688,"children":1691},{"href":1689,"rel":1690},"https:\u002F\u002Fdev.classmethod.jp\u002Farticles\u002Fcli-session\u002F",[1402],[1692],{"type":26,"value":1693},"DevelopersIO",{"type":26,"value":1662},{"type":21,"tag":22,"props":1696,"children":1697},{},[1698],{"type":26,"value":1699},"Read from vendor documentation on 2 November 2026; error strings quoted.",{"type":21,"tag":1701,"props":1702,"children":1703},"style",{},[1704],{"type":26,"value":1705},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":7,"searchDepth":685,"depth":685,"links":1707},[1708,1709,1710,1711,1712,1713,1714],{"id":45,"depth":685,"text":48},{"id":107,"depth":685,"text":110},{"id":301,"depth":685,"text":304},{"id":634,"depth":685,"text":637},{"id":1360,"depth":685,"text":1363},{"id":1410,"depth":685,"text":1413},{"id":1538,"depth":685,"text":1541},"markdown","content:blog:assumerole-chaining-one-hour-ceiling.md","content","blog\u002Fassumerole-chaining-one-hour-ceiling.md","blog\u002Fassumerole-chaining-one-hour-ceiling","md",1793619138049]