I am trying to use PreventUserExistenceErrors on a Cognito pool with a user migration Lambda trigger. Cognito documentation says:
With user migration Lambda trigger, Cognito will return a simulated response for non existing users when an empty response was returned by the Lambda trigger.
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-managing-errors.html
I don't know how to get this to work. I isolated this by setting up a pool and attaching a simple trigger which always returns an empty response (we're writing the triggers in Go on the project):
package main
import (
"fmt"
"github.com/aws/aws-lambda-go/lambda"
)
func Handle(event interface{}) (interface{}, error) {
fmt.Println("nil")
// also tried:
// return struct{}{}, nil
// return "", nil
return nil, nil
}
func main() {
lambda.Start(func(event interface{}) (interface{}, error) {
return Handle(event)
})
}
I wrote a client to try to log in to the pool with a username that doesn't exist. With the PreventUserExistenceErrors enabled I expect the error to be the same as if the trigger was not attached to the pool:
Error executing "InitiateAuth" on "https://cognito-idp.eu-west-1.amazonaws.com"; AWS HTTP error: Client error: `POST https://cognito-idp.eu-west-1.amazonaws.com` resulted in a `400 Bad Request` response:
{"__type":"NotAuthorizedException","message":"Incorrect username or password."}
But I get a different error that shows the trigger failed:
HTTP error: Client error: `POST https://cognito-idp.eu-west-1.amazonaws.com` resulted in a `400 Bad Request` response:
{"__type":"UserNotFoundException","message":"Exception migrating user in app client 4i2oaatugssocd44d40kb55kni"}
I tried returning nil, empty string and empty struct and all three show the error from the trigger.
What's the correct way to return "empty response" from Cognito Lambda trigger in Go?
Related
The golang operator started writing an error.
failed to list v1.Secret: secrets is forbidden: User "system:serviceaccount:operator-*****" cannot list resource "secrets" in API group "" in the namespace "namespace-name"
The error appeared after we enabled restrictions on list secret (set resource Names).
Without restrictions, everything works fine.
I am not familiar with golang, but after looking at the source code, I came to the conclusion that the error occurs in this place
if err := g.client.Get(ctx, client.ObjectKey{Name: tokens.Name, Namespace: g.namespace}, &tokens); err != nil {
return nil, errors.WithMessage(err, "failed to query tokens")
Here is a more complete part of the code
package initgeneration
import (
"context"
"encoding/json"
dynatracev1beta1 "github.com/Dynatrace/dynatrace-operator/src/api/v1beta1"
"github.com/Dynatrace/dynatrace-operator/src/config"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// InitGenerator manages the init secret generation for the user namespaces.
type InitGenerator struct {
client client.Client
apiReader client.Reader
namespace string
canWatchNodes bool
dynakubeQuery kubeobjects.DynakubeQuery
}
...
func (g *InitGenerator) createSecretConfigForDynaKube(ctx context.Context, dynakube *dynatracev1beta1.DynaKube, kubeSystemUID types.UID, hostMonitoringNodes map[string]string) (*standalone.SecretConfig, error) {
var tokens corev1.Secret
if err := g.client.Get(ctx, client.ObjectKey{Name: tokens.Name, Namespace: g.namespace}, &tokens); err != nil {
return nil, errors.WithMessage(err, "failed to query tokens")
The Get method is used in the package "asus.k8s.io/controller-runtime/pkg/client " , when accessing the K8S API, it requests all the secrets and only then imposes a filter.
I need to get around this limitation
How to get secrets, how to access the K8S API through the client package with a restriction on resourceName?
Controller-runtime client ( "sigs.k8s.io/controller-runtime/pkg/client") goes to its cache when receiving a request, and it updates the cache through the watch operation, i.e. it needs access to all secrets
The solution that helped: disable cache for secrets in "Options"
https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Options
via ClientDisableCacheFor
func (provider operatorManagerProvider) createOptions(namespace string) ctrl.Options {
return ctrl.Options{
Namespace: namespace,
Scheme: scheme.Scheme,
MetricsBindAddress: metricsBindAddress,
Port: operatorManagerPort,
...
ClientDisableCacheFor: []client.Object{
&corev1.Secret{},
},
}
}
I am trying to implement iamcredentials Go API client to generate an Access Token to access some Google APIs via REST API, I am using this code
package main
import (
"context"
"log"
"google.golang.org/api/iamcredentials/v1"
)
func main() {
iamcredentialsService, err := iamcredentials.NewService(context.Background())
if err != nil {
log.Println("error initialize iamcredential Service ", err)
return
}
accessTokenCall := iamcredentialsService.Projects.ServiceAccounts.GenerateAccessToken(
"projects/-/serviceAccounts/some-sa#some-project-id.iam.gserviceaccount.com:generateAccessToken",
&iamcredentials.GenerateAccessTokenRequest{
Scope: []string{
iamcredentials.CloudPlatformScope,
},
},
)
iamResp, err := accessTokenCall.Do()
if err != nil {
log.Println("error generate access token", err)
return
}
log.Println(iamResp)
}
But when I tried to run the above snippet, I got this message
go run main.go
error generate access token googleapi: Error 400: Request contains an invalid argument., badRequest
Is there any way to check which one is causing the above response? I am not sure since there isn't any good example of implementation. Any help would be appreciated, Thanks.
Notes :
I have checked following documentation on this topic https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials and this https://pkg.go.dev/google.golang.org/api/iamcredentials/v1#pkg-overview
I have already setup the Service account using Service Account Token Creator role on IAM and also enabled the IAM API from the console
Also I have added GOOGLE_APPLICATION_CREDENTIALS to the environment variables as suggested
#DanielFarrell is right, you need to remove the :generateAccessToken at the end. Here the documentation in the code. Don't hesitate to explore it, it's open source ;)
// GenerateAccessToken: Generates an OAuth 2.0 access token for a
// service account.
//
// - name: The resource name of the service account for which the
// credentials are requested, in the following format:
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-`
// wildcard character is required; replacing it with a project ID is
// invalid.
func (r *ProjectsServiceAccountsService) GenerateAccessToken(name string, generateaccesstokenrequest *GenerateAccessTokenRequest) *ProjectsServiceAccountsGenerateAccessTokenCall {
c := &ProjectsServiceAccountsGenerateAccessTokenCall{s: r.s, urlParams_: make(gensupport.URLParams)}
c.name = name
c.generateaccesstokenrequest = generateaccesstokenrequest
return c
}
I'm trying to deploy a Google Cloud Function using the go client package by google.
(https://pkg.go.dev/google.golang.org/api/cloudfunctions/v1?tab=doc#pkg-overview)
I have broken it down into the snippet I think is most relevant:
import (
"context"
log "github.com/sirupsen/logrus"
functions "google.golang.org/api/cloudfunctions/v1"
)
func main() {
ctx := context.Background()
CloudFunctionService, err := functions.NewService(ctx)
if err != nil {
log.Printf("Error at functions.NewService(ctx): \"%v\"\n", err)
}
FunctionSpec := functions.CloudFunction{
EntryPoint: "DeployThisFunctionEntryPoint",
EventTrigger: &functions.EventTrigger{
EventType: "google.pubsub.topic.publish",
Resource: "projects/mytestproject/topics/cloud-builds",
},
Name: "DeployThisFunction",
Runtime: "go111",
SourceRepository: &functions.SourceRepository{Url: "https://source.developers.google.com/projects/mytestproject/repos/deploythisfunction/moveable-aliases/master/paths//"},
}
CloudFunctionDeploymentService := functions.NewProjectsLocationsFunctionsService(CloudFunctionService)
createCall := CloudFunctionDeploymentService.Create("projects/mytestproject/locations/us-central1", &FunctionSpec)
resp, err := createCall.Context(ctx).Do()
if err != nil {
log.Printf("Error at createCall.Context(ctx).Do(): \"%v\"\n", err)
}
log.Printf("response createCall.Context(ctx).Do(): \"%v\"\n", resp)
}
However, no matter how I format it or try. I always get the following message:
googleapi: Error 400: Precondition check failed., failedPrecondition
Through the google api explorer I ran the request with their authentication and json scheme and I received the same error.
https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions/create
Response:
{
"error": {
"code": 400,
"message": "Precondition check failed.",
"status": "FAILED_PRECONDITION"
}
}
I cannot figure out what is going wrong. I have started my own project and am the administrator. When running another part of the go client with GCP for instance creating storage, IAM user, serviceaccounts, database I can make it work and create these resources.
If anyone has encountered this problem I would appreciate some help.
The eventType should match pattern : providers/*/eventTypes/*.*. .
For exmple:providers/cloud.pubsub/eventTypes/topic.publish
Also SourceRepository url should be https://source.developers.google.com/projects/*/repos/*/revisions/*/paths/
and you have https://source.developers.google.com/projects/mytestproject/repos/deploythisfunction/moveable-aliases/master/paths//
The error message says that is an issue with the way you configure FunctionSpec, I suspect EventTrigger or SourceRepository fields.
Edit
The code: 400 is a bad request, client error, in this case formatting issue, and the first thing to check is each cloud function fileds
I'm following the Creating HTTP Target tasks guide.
When I run the code posted below I get this error:
cloudtasks.CreateTask: rpc error: code = PermissionDenied
desc = The principal (user or service account)
lacks IAM permission "cloudtasks.tasks.create" for the resource
"projects/my_project/locations/europe-west1/queues/my_queue"
(or the resource may not exist).
I have signed in with gcloud auth login my#email.com.
my#email.com has the following permissions set by my custom cloud task role:
cloudtasks.locations.get
cloudtasks.locations.list
cloudtasks.queues.get
cloudtasks.queues.list
cloudtasks.tasks.create
cloudtasks.tasks.delete
cloudtasks.tasks.fullView
cloudtasks.tasks.get
cloudtasks.tasks.list
cloudtasks.tasks.run
I don't get it. What more should I check?
main.go
// Run `PROJECT_ID=my_project QUEUE_ID=my_queue go run main.go`
package main
import (
"context"
"fmt"
"os"
cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
)
var (
locationID = "europe-west1"
url = "example.com/callback"
message = "testing"
)
func main() {
projectID := os.Getenv("PROJECT_ID")
queueID := os.Getenv("QUEUE_ID")
task, err := createHTTPTask(projectID, locationID, queueID, url, message)
if err != nil {
fmt.Println(err)
}
fmt.Println(task)
}
// createHTTPTask creates a new task with a HTTP target then adds it to a Queue.
func createHTTPTask(projectID, locationID, queueID, url, message string) (*taskspb.Task, error) {
// Create a new Cloud Tasks client instance.
// See https://godoc.org/cloud.google.com/go/cloudtasks/apiv2
ctx := context.Background()
client, err := cloudtasks.NewClient(ctx)
if err != nil {
return nil, fmt.Errorf("NewClient: %v", err)
}
// Build the Task queue path.
queuePath := fmt.Sprintf("projects/%s/locations/%s/queues/%s", projectID, locationID, queueID)
// Build the Task payload.
// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#CreateTaskRequest
req := &taskspb.CreateTaskRequest{
Parent: queuePath,
Task: &taskspb.Task{
// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#HttpRequest
MessageType: &taskspb.Task_HttpRequest{
HttpRequest: &taskspb.HttpRequest{
HttpMethod: taskspb.HttpMethod_POST,
Url: url,
},
},
},
}
// Add a payload message if one is present.
req.Task.GetHttpRequest().Body = []byte(message)
createdTask, err := client.CreateTask(ctx, req)
if err != nil {
return nil, fmt.Errorf("cloudtasks.CreateTask: %v", err)
}
return createdTask, nil
}
The Cloud Tasks API is enabled.
I've been having the same issue for the past couple of days and figured it out. The library I was using to create the API client and create a task was using different credentials than I expected.
For those that are using "application default credentials", or at least letting the client find credentials automatically, take a look at this page: https://cloud.google.com/docs/authentication/production#finding_credentials_automatically
I had created a service account with all the right roles and was assuming the API client was using the service account. Turns out I wasn't passing in the key file and thus it was using the "application default credentials". For my use case, "application default credentials" referred to the App Engine default service account. When I supplied the API client with a key file for my custom service account, it worked.
Application Default Credentials (ADC) provide a method to get credentials used in calling Google APIs. The gcloud auth application-default command group allows you to manage active credentials on your machine that are used for local application development.
Acquire new user credentials to use for ADC with the following command:
gcloud auth application-default login
I'm trying to write a twitter reader that resolves the final URLs of link shorteners etc, but gives me a URL along the way for a list of manually defined host patterns. The reason to do this is that i don't want to end up with the paywall URL but the one before.
As far as i can tell the way to do this is write my own client based on the default RoundTripper because returning an error from a custom CheckRedirect function aborts the client without yielding a response.
Is there a way to use the default client and record a list of URLs/specific URL from a custom checkRedirect function?
The client request will actually still return the last valid Response in cases where your custom CheckResponse yields an error (As mentioned in the comments).
http://golang.org/pkg/net/http/#Client
If CheckRedirect returns an error, the Client's Get method returns both the previous Response and CheckRedirect's error (wrapped in a url.Error) instead of issuing the Request req.
If you maintain a list of "known" paywall-urls, you can abort the paywall-redirect in your CheckResponse with a custom error type (Paywalled in the example below).
Your error handling code later has to consider that error type as a special (non-erroneous) case.
Example:
package main
import (
"errors"
"fmt"
"net/http"
"net/url"
)
var Paywalled = errors.New("next redirect would hit a paywall")
var badHosts = map[string]error{
"registration.ft.com": Paywalled,
}
var client = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// N.B.: when used in production, also check for redirect loops
return badHosts[req.URL.Host]
},
}
func main() {
resp, err := client.Get("http://on.ft.com/14pQBYE")
// ignore non-nil err if it's a `Paywalled` wrapped in url.Error
if e, ok := err.(*url.Error); (ok && e.Err != Paywalled) || (!ok && err != nil) {
fmt.Println("error: ", err)
return
}
resp.Body.Close()
fmt.Println(resp.Request.URL)
}