Skip to content

Commit 0b03704

Browse files
blink1073pmeredit
andauthored
GODRIVER-2758: Add documentation examples [master] (#1801)
Co-authored-by: Patrick Meredith <[email protected]>
1 parent 9e7ccb0 commit 0b03704

File tree

2 files changed

+267
-2
lines changed

2 files changed

+267
-2
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ repos:
4040
rev: "v2.2.6"
4141
hooks:
4242
- id: codespell
43-
args: ["-L", "te,fo,fle,alo,nin,compres,wil,collone,asess,sav,ot,wll,dne,nulll,hellow"]
44-
exclude: ^(vendor/|internal/cmd/benchmark/operation_test.go|bson/testdata/lorem.txt)
43+
args: ["-L", "te,fo,fle,alo,nin,compres,wil,collone,asess,sav,ot,wll,dne,nulll,hellow,aks"]
44+
exclude: ^(vendor/|internal/cmd/benchmark/operation_test.go|bson/testdata/)
4545
exclude_types: [json,yaml,pem]
4646

4747
- repo: https://github.com/tcort/markdown-link-check

mongo/client_examples_test.go

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"context"
1111
"fmt"
1212
"log"
13+
"os"
1314

1415
"go.mongodb.org/mongo-driver/v2/bson"
1516
"go.mongodb.org/mongo-driver/v2/mongo"
@@ -459,3 +460,267 @@ func ExampleConnect_bSONOptions() {
459460
panic(err)
460461
}
461462
}
463+
464+
func ExampleConnect_oIDC() {
465+
// The `MONGODB-OIDC authentication mechanism` is available in MongoDB 7.0+
466+
// on Linux platforms.
467+
//
468+
// The MONGODB-OIDC mechanism authenticates using an OpenID Connect (OIDC)
469+
// access token. The driver supports OIDC for workload identity, defined as
470+
// an identity you assign to a software workload (such as an application,
471+
// service, script, or container) to authenticate and access other services
472+
// and resources.
473+
//
474+
// The driver also supports OIDC for workforce identity for a more secure
475+
// flow with a human in the loop.
476+
477+
// Credentials can be configured through the MongoDB URI or as arguments in
478+
// the options.ClientOptions struct that is passed into the mongo.Connect
479+
// function.
480+
481+
// Built-in Support
482+
// The driver has built-in support for Azure IMDS and GCP
483+
// IMDS environments. Other environments are supported with `Custom
484+
// Callbacks`.
485+
486+
// Azure IMDS
487+
// For an application running on an Azure VM or otherwise using the `Azure
488+
// Internal Metadata Service`, you can use the built-in support for Azure,
489+
// where "<client_id>" below is the client id of the Azure managed identity,
490+
// and ``<audience>`` is the url-encoded ``audience`` `configured on your
491+
// MongoDB deployment`.
492+
{
493+
uri := os.Getenv("MONGODB_URI")
494+
props := map[string]string{
495+
"ENVIRONMENT": "azure",
496+
"TOKEN_RESOURCE": "<audience>",
497+
}
498+
opts := options.Client().ApplyURI(uri)
499+
opts.SetAuth(
500+
options.Credential{
501+
Username: "<client_id>",
502+
AuthMechanism: "MONGODB-OIDC",
503+
AuthMechanismProperties: props,
504+
},
505+
)
506+
c, err := mongo.Connect(opts)
507+
if err != nil {
508+
panic(err)
509+
}
510+
defer func() { _ = c.Disconnect(context.TODO()) }()
511+
_, err = c.Database("test").
512+
Collection("test").
513+
InsertOne(context.TODO(), bson.D{})
514+
if err != nil {
515+
panic(err)
516+
}
517+
}
518+
519+
// If the application is running on an Azure VM and only one managed
520+
// identity is associated with the VM, "username" can be omitted.
521+
522+
// GCP IMDS
523+
524+
// For an application running on an GCP VM or otherwise using the `GCP
525+
// Internal Metadata Service`_, you can use the built-in support for GCP,
526+
// where "<audience>" below is the url-encoded "audience" `configured on
527+
// your MongoDB deployment`.
528+
{
529+
uri := os.Getenv("MONGODB_URI")
530+
props := map[string]string{
531+
"ENVIRONMENT": "gcp",
532+
"TOKEN_RESOURCE": "<audience>",
533+
}
534+
opts := options.Client().ApplyURI(uri)
535+
opts.SetAuth(
536+
options.Credential{
537+
AuthMechanism: "MONGODB-OIDC",
538+
AuthMechanismProperties: props,
539+
},
540+
)
541+
c, err := mongo.Connect(opts)
542+
if err != nil {
543+
panic(err)
544+
}
545+
defer func() { _ = c.Disconnect(context.TODO()) }()
546+
_, err = c.Database("test").
547+
Collection("test").
548+
InsertOne(context.TODO(), bson.D{})
549+
if err != nil {
550+
panic(err)
551+
}
552+
}
553+
554+
// Custom Callbacks
555+
556+
// For environments that are not directly supported by the driver, you can
557+
// use options.OIDCCallback. Some examples are given below.
558+
559+
// AWS EKS
560+
561+
// For an EKS Cluster with a configured `IAM OIDC provider`, the token can
562+
// be read from a path given by the "AWS_WEB_IDENTITY_TOKEN_FILE"
563+
// environment variable.
564+
{
565+
eksCallback := func(_ context.Context,
566+
_ *options.OIDCArgs) (*options.OIDCCredential, error) {
567+
accessToken, err := os.ReadFile(
568+
os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE"))
569+
if err != nil {
570+
return nil, err
571+
}
572+
return &options.OIDCCredential{
573+
AccessToken: string(accessToken),
574+
}, nil
575+
}
576+
uri := os.Getenv("MONGODB_URI")
577+
props := map[string]string{
578+
"ENVIRONMENT": "gcp",
579+
"TOKEN_RESOURCE": "<audience>",
580+
}
581+
opts := options.Client().ApplyURI(uri)
582+
opts.SetAuth(
583+
options.Credential{
584+
AuthMechanism: "MONGODB-OIDC",
585+
AuthMechanismProperties: props,
586+
OIDCMachineCallback: eksCallback,
587+
},
588+
)
589+
c, err := mongo.Connect(opts)
590+
if err != nil {
591+
panic(err)
592+
}
593+
defer func() { _ = c.Disconnect(context.TODO()) }()
594+
_, err = c.Database("test").
595+
Collection("test").
596+
InsertOne(context.TODO(), bson.D{})
597+
if err != nil {
598+
panic(err)
599+
}
600+
}
601+
602+
// Other Azure Environments
603+
604+
// For applications running on Azure Functions, App Service Environment
605+
// (ASE), or Azure Kubernetes Service (AKS), you can use the `azidentity
606+
// package`
607+
// (https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity) to
608+
// fetch the credentials. In each case, the OIDCCallback function should
609+
// return the AccessToken from the azidentity package.
610+
611+
// GCP GKE
612+
613+
// For a Google Kubernetes Engine cluster with a `configured service
614+
// account`, the token can be read from the standard service account token
615+
// file location.
616+
{
617+
gkeCallback := func(_ context.Context,
618+
_ *options.OIDCArgs) (*options.OIDCCredential, error) {
619+
accessToken, err := os.ReadFile(
620+
"/var/run/secrets/kubernetes.io/serviceaccount/token")
621+
if err != nil {
622+
return nil, err
623+
}
624+
return &options.OIDCCredential{
625+
AccessToken: string(accessToken),
626+
}, nil
627+
}
628+
uri := os.Getenv("MONGODB_URI")
629+
props := map[string]string{
630+
"ENVIRONMENT": "gcp",
631+
"TOKEN_RESOURCE": "<audience>",
632+
}
633+
opts := options.Client().ApplyURI(uri)
634+
opts.SetAuth(
635+
options.Credential{
636+
AuthMechanism: "MONGODB-OIDC",
637+
AuthMechanismProperties: props,
638+
OIDCMachineCallback: gkeCallback,
639+
},
640+
)
641+
c, err := mongo.Connect(opts)
642+
if err != nil {
643+
panic(err)
644+
}
645+
defer func() { _ = c.Disconnect(context.TODO()) }()
646+
_, err = c.Database("test").
647+
Collection("test").
648+
InsertOne(context.TODO(), bson.D{})
649+
if err != nil {
650+
panic(err)
651+
}
652+
}
653+
654+
// For workforce identity, the Client must be configured with the
655+
// OIDCHumanCallback rather than the OIDCMachineCallback. The
656+
// OIDCHumanCallback is used by the driver in a process that is two step. In
657+
// the first step, the driver retrieves the Identity Provider (IDP)
658+
// Information (IDPInfo) for the passed username. The OIDCHumanCallback then
659+
// needs to negotiate with the IDP in order to obtain an AccessToken,
660+
// possible RefreshToken, any timeouts, and return them, similar to the
661+
// OIDCMachineCallbacks seen above. See
662+
// https://docs.hidglobal.com/dev/auth-service/integration/openid-authentication-flows.html
663+
// for more information on various OIDC authentication flows.
664+
{
665+
humanCallback := func(ctx context.Context,
666+
opts *options.OIDCArgs) (*options.OIDCCredential, error) {
667+
// idpInfo passed from the driver by asking the MongoDB server for
668+
// the info configured for the username
669+
idpInfo := opts.IDPInfo
670+
// negotiateWithIDP must work with the IdP to obtain an access
671+
// token. In many cases this will involve opening a webbrowser or
672+
// providing a URL on the command line to a human-in-the-loop who
673+
// can give permissions to the IdP.
674+
accessToken, err := negotiateWithIDP(ctx, idpInfo.Issuer)
675+
if err != nil {
676+
return nil, err
677+
}
678+
return &options.OIDCCredential{
679+
AccessToken: accessToken,
680+
}, nil
681+
}
682+
uri := os.Getenv("MONGODB_URI")
683+
props := map[string]string{
684+
"ENVIRONMENT": "gcp",
685+
"TOKEN_RESOURCE": "<audience>",
686+
}
687+
opts := options.Client().ApplyURI(uri)
688+
opts.SetAuth(
689+
options.Credential{
690+
AuthMechanism: "MONGODB-OIDC",
691+
AuthMechanismProperties: props,
692+
OIDCHumanCallback: humanCallback,
693+
},
694+
)
695+
c, err := mongo.Connect(opts)
696+
if err != nil {
697+
panic(err)
698+
}
699+
defer func() { _ = c.Disconnect(context.TODO()) }()
700+
_, err = c.Database("test").
701+
Collection("test").
702+
InsertOne(context.TODO(), bson.D{})
703+
if err != nil {
704+
panic(err)
705+
}
706+
}
707+
708+
// * MONGODB-OIDC authentication mechanism:
709+
// https://www.mongodb.com/docs/manual/core/security-oidc/
710+
// * OIDC Identity Provider Configuration:
711+
// https://www.mongodb.com/docs/manual/reference/parameters/#mongodb-parameter-param.oidcIdentityProviders
712+
// * Azure Internal Metadata Service:
713+
// https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service
714+
// * GCP Internal Metadata Service:
715+
// https://cloud.google.com/compute/docs/metadata/querying-metadata
716+
// * IAM OIDC provider:
717+
// https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html
718+
// * azure-identity package:
719+
// https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity
720+
// * configured service account:
721+
// https://cloud.google.com/kubernetes-engine/docs/how-to/service-accounts
722+
}
723+
724+
func negotiateWithIDP(_ context.Context, _ string) (string, error) {
725+
return "", nil
726+
}

0 commit comments

Comments
 (0)