buildCredentialChainSecret builds a CREATE SECRET statement using AWS SDK credential chain
(dlCfg DuckLakeConfig)
| 2147 | } |
| 2148 | |
| 2149 | if _, err := db.Exec(secretStmt); err != nil { |
| 2150 | return err |
| 2151 | } |
| 2152 | |
| 2153 | slog.Info("Created S3 secret successfully.") |
| 2154 | return nil |
| 2155 | } |
| 2156 | |
| 2157 | // RefreshS3Secret replaces the DuckDB S3 secret with updated credentials. |
| 2158 | // Used when a hot-idle worker is reclaimed and STS credentials have rotated. |
| 2159 | // Respects the configured S3 provider (config, aws_sdk, credential_chain). |
| 2160 | func RefreshS3Secret(db *sql.DB, dlCfg DuckLakeConfig, duckLakeSem chan struct{}) error { |
| 2161 | if dlCfg.ObjectStore == "" { |
| 2162 | return nil |
| 2163 | } |
| 2164 | ae := newAttachStepExecer(db) |
| 2165 | if duckLakeSem != nil { |
| 2166 | duckLakeSem <- struct{}{} |
| 2167 | defer ae.releaseSem(duckLakeSem) |
| 2168 | } |
| 2169 | |
| 2170 | provider := S3ProviderForConfig(dlCfg) |
| 2171 | var secretStmt string |
| 2172 | switch provider { |
| 2173 | case "aws_sdk": |
| 2174 | sdkCtx, sdkCancel := context.WithTimeout(context.Background(), attachStepTimeout) |
| 2175 | defer sdkCancel() |
| 2176 | var err error |
| 2177 | secretStmt, err = buildAWSSdkSecret(sdkCtx, dlCfg) |
| 2178 | if err != nil { |
| 2179 | return fmt.Errorf("refresh aws_sdk S3 secret: %w", err) |
| 2180 | } |
| 2181 | case "credential_chain": |
| 2182 | secretStmt = buildCredentialChainSecret(dlCfg) |
| 2183 | default: |
| 2184 | secretStmt = buildConfigSecret(dlCfg) |
| 2185 | } |
| 2186 | |
| 2187 | // If the previous session left the connection in DuckDB's "Current |
| 2188 | // transaction is aborted" state, the exec will always fail. Issue a |
| 2189 | // ROLLBACK to recover, matching the pattern in StartCredentialRefresh. |
| 2190 | if _, err := ae.Exec(secretStmt); err != nil { |
| 2191 | if isTransactionAborted(err) { |
| 2192 | _, _ = ae.Exec("ROLLBACK") |