如何在定时任务中向受保护的 API 端点发送授权请求?

huangapple go评论104阅读模式
英文:

How can I make authorized requests to secured API endpoint from cronjobs?

问题

我有一个使用JWT令牌进行API密钥授权的Golang应用程序。

我正在使用Kubernetes。所以,这个Golang应用程序在一个Pod中。

现在,我想创建另一个应用程序,用于定时任务,每周调用Golang端点一次。

我需要的是:

如何执行/跳过授权?

跳过:这里不需要Ingress,因为我可以直接在内部调用它。这对这种情况有帮助吗?

我尝试过的:

我尝试将定时任务和API放在同一个应用程序中,这样我可以简单地调用服务而不是端点,但这也有一个缺点。
我无法创建副本,因为它们也会复制定时任务,并且会多次命中相同的端点1*副本数次。

我想每周调用"abc.com"端点。它需要一个令牌,我不能简单地传递一个令牌。
我希望有某种解决方法。

英文:

I have a golang application which has API key authorization via the JWT token

I am using Kubernetes. So, this golang app is in a pod.

Now, I want to create another application for cronjobs to hit golang endpoint once a week.

What I need:

How to do / skip the authorization?

skip: Ingress is not required here as I can simply call it internally. Can that help this case?

What I Tried:

I tried keeping the cronjobs and api in the same application so I can simply call the service instead of the endpoint, But that also has a drawback.
I am not able to create replicas as they will also replicate the cronjobs and the same endpoint will be hit 1*no of replicas times

I want to call "abc.com" endpoint once a week. It requires a token and I cannot simply pass a token.
I hope there is some way around this.

答案1

得分: 0

如果你只是在内部调用它们而不暴露它们,那肯定会有帮助。
只要两个Pod(因此也是Deployments)在同一个集群下运行,你就可以使用Kubernetes的内部DNS。

Kubernetes会自动为你创建的服务创建DNS记录,可以按照特定格式用于内部通信:<service-name>.<service-namespace>.svc.cluster.local

官方文档中有更多信息:Services and Pods的DNS

如果听起来很奇怪,或者如果它有助于理解要点,可以尝试将“endpoint”视为添加到系统hosts文件的规则:基本上是添加一个规则,其中<service-name>.<service-namespace>.svc.cluster.local指向你的Pod的IP地址,只不过这是自动完成的。

例如:

  • 你的golang应用程序在一个Pod中运行。
  • 你创建了一个指向该应用程序的Service,命名为go-api,位于命名空间go-apps下。
  • 如果你的cron-job worker也在同一个集群中的一个Pod中运行,你可以使用go-api.go-apps.svc.cluster.local[:<port>]来访问你的应用程序,而不需要使用Ingress。

授权取决于你,因为通常你要么直接处理它,要么使用特定的框架来处理。例如,你可以在应用程序中添加一个自定义的端点路径,确保只有来自集群相同的私有IP子网的客户端被接受,可以选择不使用令牌(不推荐),或者使用一个你生成和控制的特定半固定令牌,这样你就可以从你的cron中发送一个请求,类似于这样:go-api.go-apps.svc.cluster.local:8080/api/v1/callWithNoAuth

英文:

If you just have to call them internally without exposing them, it can certainly help.<br>
Provided both Pods (and therefore Deployments) are running under the same Cluster you can use Kubernetes' internal DNS.

K8s automatically creates DNS records for Services you create that can be used for internal communication by following this specific format: &lt;service-name&gt;.&lt;service-namespace&gt;.svc.cluster.local

More information from the official docs here: DNS for Services and Pods

If it sounds weird or if it can help understanding the gist of it, try to think of the "endpoint" as a rule you add to your system's hosts file: it boils down to basicly adding a rule where &lt;service-name&gt;.&lt;service-namespace&gt;.svc.cluster.local points to your pod's IP address, except it's done automatically

E.g.<br>

  • Your golang app is running inside a Pod.
  • You created a Service pointing to it, named go-api and under the namespace go-apps.
  • If your cron-job worker is running in a Pod inside the same cluster, you can use go-api.go-apps.svc.cluster.local[:&lt;port&gt;] to reach your app without using an Ingress

The authorization is up to you, since you're usually handling it either directly or by using specific frameworks.
You could, for example, add a custom endpoint path inside your app where you make sure that the only accepted clients come from the same, private IP subnet of your cluster, either without a token (not recommended) or with a specific semi-fixed one that you generate and control, so that you would send a request to something like this from your crons: go-api.go-apps.svc.cluster.local:8080/api/v1/callWithNoAuth

答案2

得分: 0

我正在创建一个新的答案,因为我觉得我有更多的观点可以贡献给这个问题。所以,我最终做的是创建一个用于内部 API 调用的中间件。在这个中间件中,我对调用者进行授权,即检查它是否来自于 "xyz-service:port"。

我发现使用第三方认证器是过度的,而在代码中使用令牌则更加危险。

由于除了入口之外的所有服务都是 ClusterIP,没有人可以直接从外部访问它。

感谢 @LeoD 的答案。我通过这种方法获得了信心。

附注:简单的 service-name:port 就足够了
例如:http://myservice:4000/api

英文:

I am creating a new answer as I feel I have more points to contribute to this.
So, what I eventually did end up doing is creating a middle-ware for internal API calls. Inside this middleware, I authorize the caller in middleware i.e. check whether it is from "xyz-service:port".

I found that the need to use a 3rd party authenticator was overkill and using a token in code was riskier.

Since all the services except for the ingress is ClusterIP, No one can access it from outside directly.

Thanks to @LeoD's answer. I gained confidence using this method.

P.S. Simply service-name:port can suffice
eg: http://myservice:4000/api

huangapple
  • 本文由 发表于 2022年11月21日 22:04:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/74520139.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定