Solución:
Estos son los pasos exactos que debe seguir. Asegúrese de no omitir el segundo paso, establece permisos de invocador para que el programador pueda invocar la función de nube HTTP.
# Create cloud function
gcloud functions deploy my_function
--entry-point=my_entrypoint
--runtime=python37
--trigger-http
--region=europe-west1
--project=${PROJECT_ID}
# Set invoke permissions
gcloud functions add-iam-policy-binding my_function
--region=europe-west1
--member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com
--role="roles/cloudfunctions.invoker"
--project=${PROJECT_ID}
# Deploy scheduler
gcloud scheduler jobs create http my_job
--schedule="every 60 minutes"
--uri="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function/"
--http-method=POST
--oidc-service-account-email="${PROJECT_ID}@appspot.gserviceaccount.com"
--oidc-token-audience="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function"
--project=${PROJECT_ID}
Pensé que ampliaría la respuesta de Nebulastic ya que acabo de descubrir que hay algunos casos extremos en los que su respuesta no está completa.
Crear función de nube
# Create cloud function
gcloud functions deploy my_function
--entry-point=my_entrypoint
--runtime=python37
--trigger-http
--region=europe-west1
--project=${PROJECT_ID}
Es posible que desee cambiar campos como entry-point
, runtime
o trigger
. Obtén más información en los documentos de implementación de Cloud Functions.
Crear trabajo de Cloud Scheduler:
# Deploy scheduler
gcloud scheduler jobs create http my_job
--schedule="every 60 minutes"
--uri="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function/"
--http-method=POST
--oidc-service-account-email="${SERVICE_ACCOUNT_EMAIL}"
--oidc-token-audience="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function"
--project=${PROJECT_ID}
Consulte los documentos de Cloud Schedule para obtener más información.
Tenga en cuenta que se puede utilizar cualquier cuenta de servicio para la autenticación OIDC, no solo la predeterminada creada para el proyecto.
Además, no necesitas llamar gcloud functions add-iam-policy-binding
como se sugiere en la respuesta de Nebulastic, pero en su lugar puede establecer el rol de invocador de Cloud Functions en la cuenta de servicio que se le pasó --oidc-service-account-email
(ver el documento sobre cómo agregar roles). De esta manera, dicha cuenta de servicio tendría permisos para llamar a cualquier Cloud Functions sin necesidad de otorgar dicho permiso en cada implementación. Esto no quiere decir que el método que sugiere Nebulastic sea incorrecto, también puede hacerlo de esa manera.
Puede verificar qué cuentas de servicio tienen permiso para llamar a la función haciendo clic en su nombre en la lista Cloud Functions -> pestaña Permisos -> subpestaña Roles -> abrir la fila Cloud Functions Invoker.
Ahora para los casos extremos:
Ingress: permitir solo tráfico interno
A pesar de lo que sugiere la documentación, establecer la configuración de entrada de la función en ‘Permitir solo tráfico interno’ no abarca el tráfico de Cloud Scheduler y dará como resultado el error PERMISSION_DENIED. Esto es algo de lo que son conscientes los desarrolladores de GCP y puede que se solucione en el futuro. Por ahora, use ‘Permitir todo el tráfico’ (o --ingress-settings=all
si se implementa con gcloud).
Parámetros de URL y autenticación OIDC
Si su trabajo de Cloud Schedule usa autenticación OIDC y su función espera argumentos en forma de parámetros de URL, p. Ej. ...my_function?key=value
– entonces debe asegurarse de que la audiencia de OIDC no contienen los parámetros de la URL. Especifique los parámetros de URL solo en el campo URL, pero si aparecen en el campo Audiencia, la solicitud devolverá 403 UNAUTHENTICATED. Tenga en cuenta que la audiencia de OIDC se completa automáticamente con una copia de la URL si no especifica la audiencia de OIDC manualmente. Este es otro problema que conocen los desarrolladores de GCP y que posiblemente estén trabajando en una solución o actualización de la documentación.
tldr: no coloque parámetros de URL en la URL de audiencia de OIDC, solo en el campo URL:
--uri="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function?key=value"
--oidc-token-audience="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function"
Parámetros JSON y tipo de contenido
Si eliges usar un trabajo de Cloud Scheduler llamando a una función con parámetros JSON, p. Ej. {"key": "value"}
en el cuerpo campo – entonces necesitará:
-
Analice el JSON manualmente en la función; por ejemplo, get_json de Flask no funcionará a menos que lo llame con
force=True
. -
Crea la función usando
gcloud scheduler jobs create
, en lugar de desde la consola, y asegúrese de especificar el encabezado Content-Type agregando la siguiente marca:--headers Content-Type=application/json
API de Cloud Scheduler habilitada antes del 19/03/2019
La cuenta de servicio de Cloud Scheduler con esta función otorgada se configura automáticamente cuando habilita la API de Cloud Scheduler, a menos que la haya habilitado antes del 19 de marzo de 2019, en cuyo caso debe agregar la función manualmente.
Esta parece ser la razón detrás del problema enumerado en la pregunta del autor. Consulte los documentos para obtener más información. La razón por la que esto causó problemas es la siguiente:
El propio Cloud Scheduler debe tener una cuenta de servicio propia que tenga el rol de Agente de servicio de Cloud Scheduler otorgado. Esto es para que pueda generar tokens de encabezado en nombre de su cuenta de servicio de cliente para autenticarse en su objetivo.
Fuentes: acabo de pasar una semana trabajando con uno de sus agentes de soporte para resolver todo esto; un saludo a Jason, que ayudó a descubrir todas estas peculiaridades. Están trabajando en estos problemas, pero pensé en dejar esta información aquí hasta que (si es que alguna vez) se aborden estos temas.