Getting started¶
By the end of this you will have one AWS credential resolution feeding two service clients, and you will have seen that constructing the source does no work at all.
1. Build a source¶
package main
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/ssm"
"gitlab.com/phpboyscout/go/awsclient"
)
func main() {
src := awsclient.Ambient(awsclient.WithRegion("eu-west-2"))
fmt.Println("source built; nothing resolved yet")
cfg, err := src.AWSConfig(context.Background())
if err != nil {
panic(err)
}
ssmClient := ssm.NewFromConfig(cfg)
s3Client := s3.NewFromConfig(cfg)
fmt.Println("two clients, one credential resolution")
_, _ = ssmClient, s3Client
}
Ambient returns immediately and performs no I/O. The chain is resolved on the
first AWSConfig call — which is what lets you build a source in a constructor
that has no context to hand, or in package init.
2. Prove the sharing¶
Ask twice and the second call does not re-resolve:
Both calls return the same resolved configuration. Concurrent callers collapse into a single attempt rather than each starting their own — which matters when the chain reaches an instance metadata service that rate-limits.
3. Forget the region and see what happens¶
It refuses rather than guessing. A guessed region means calling a key in an account nobody named — so the module declines, and you decide.
You can also let the environment supply it:
4. Try again after a failure¶
Take the region away, ask, fail — then set it and ask again. The second call succeeds. Failures are never cached, so a credential chain that was not ready when your process started is picked up by the next attempt rather than requiring a restart.
That behaviour comes from
go/clientlifecycle, which holds
the state machine every provider module here shares.