buildAWSSdkSecret fetches credentials via the Go AWS SDK and builds a CREATE SECRET statement with PROVIDER config using the explicit temporary credentials.
(ctx context.Context, dlCfg DuckLakeConfig)
| 2212 | // RefreshS3Secret replaces the DuckDB S3 secret with updated credentials. |
| 2213 | // Used when a hot-idle worker is reclaimed and STS credentials have rotated. |
| 2214 | // Respects the configured S3 provider (config, aws_sdk, credential_chain). |
| 2215 | func RefreshS3Secret(db *sql.DB, dlCfg DuckLakeConfig, duckLakeSem chan struct{}) error { |
| 2216 | if dlCfg.ObjectStore == "" { |
| 2217 | return nil |
| 2218 | } |
| 2219 | ae := newAttachStepExecer(db) |
| 2220 | if duckLakeSem != nil { |
| 2221 | duckLakeSem <- struct{}{} |
| 2222 | defer ae.releaseSem(duckLakeSem) |
| 2223 | } |
| 2224 | |
| 2225 | provider := S3ProviderForConfig(dlCfg) |
| 2226 | var secretStmt string |
| 2227 | switch provider { |
| 2228 | case "aws_sdk": |
| 2229 | sdkCtx, sdkCancel := context.WithTimeout(context.Background(), attachStepTimeout) |
| 2230 | defer sdkCancel() |
| 2231 | var err error |
| 2232 | secretStmt, err = buildAWSSdkSecret(sdkCtx, dlCfg) |
| 2233 | if err != nil { |
| 2234 | return fmt.Errorf("refresh aws_sdk S3 secret: %w", err) |
| 2235 | } |
| 2236 | case "credential_chain": |
| 2237 | secretStmt = buildCredentialChainSecret(dlCfg) |
| 2238 | default: |
| 2239 | secretStmt = buildConfigSecret(dlCfg) |
| 2240 | } |
| 2241 | |
| 2242 | // If the previous session left the connection in DuckDB's "Current |
| 2243 | // transaction is aborted" state, the exec will always fail. Issue a |
| 2244 | // ROLLBACK to recover, matching the pattern in StartCredentialRefresh. |
| 2245 | if _, err := ae.Exec(secretStmt); err != nil { |
| 2246 | if isTransactionAborted(err) { |
| 2247 | _, _ = ae.Exec("ROLLBACK") |
| 2248 | if _, retryErr := ae.Exec(secretStmt); retryErr != nil { |
| 2249 | return fmt.Errorf("refresh S3 secret after rollback: %s", redactSecretStatementError(retryErr.Error())) |
| 2250 | } |
| 2251 | } else { |
| 2252 | return fmt.Errorf("refresh S3 secret: %s", redactSecretStatementError(err.Error())) |
| 2253 | } |
| 2254 | } |
| 2255 | slog.Debug("Refreshed S3 secret for hot-idle reuse.", "provider", provider) |
no test coverage detected