11import pulumi
2- import pulumi_gcp as gcp
2+ import pulumi_gcp as gcp
3+ import pulumi_random as random
4+ import utils
35
4- # Be careful editing this file, if you are unfamiliar with Pulumi or the Google Cloud Platform.
5- # Make sure you read the README.md in the root of this repository first.
6+ gcp_config = pulumi .Config ("gcp" )
7+ LOCATION = gcp_config .require ("region" )
8+ STACK_NAME = pulumi .get_stack ()
69
7- # setup infrastructure
10+ project_id = random .RandomPet ("project-id" ,
11+ length = 2
12+ )
813
9- PROJECT_ID = "osakunta-telegram-bot"
10- LOCATION = "europe-north1"
14+ project = gcp .organizations .Project ("project" ,
15+ name = f"Telegram Bot { STACK_NAME } " ,
16+ project_id = project_id .id ,
17+ folder_id = "452932952214"
18+ )
1119
12- # Set up secret to hold the Telegram API token
13- telegram_bot_token = gcp .secretmanager .Secret ("telegram-bot-token" ,
14- secret_id = "telegram-bot-token" ,
20+ # Enable required services / APIs
21+ secretmanager_service = gcp .projects .Service ("secretmanager-service" ,
22+ project = project_id .id ,
23+ service = "secretmanager.googleapis.com" ,
24+ disable_on_destroy = True
25+ )
26+
27+ cloudbuild_service = gcp .projects .Service ("cloudbuild-service" ,
28+ project = project_id .id ,
29+ service = "cloudbuild.googleapis.com" ,
30+ disable_on_destroy = True
31+ )
32+
33+ cloudrun_service = gcp .projects .Service ("cloudrun-service" ,
34+ project = project_id .id ,
35+ service = "run.googleapis.com" ,
36+ disable_on_destroy = True
37+ )
38+
39+ cloudfunctions_service = gcp .projects .Service ("cloudfunctions-service" ,
40+ project = project_id .id ,
41+ service = "cloudfunctions.googleapis.com" ,
42+ disable_on_destroy = True
43+ )
44+
45+ cloudresourcemanager_service = gcp .projects .Service ("cloudresourcemanager-service" ,
46+ project = project_id .id ,
47+ service = "cloudresourcemanager.googleapis.com" ,
48+ disable_on_destroy = True
49+ )
50+
51+
52+ # --- Set up github repo connection ---
53+ github_token_secret = gcp .secretmanager .Secret ("github-token-secret" ,
54+ project = project_id .id ,
55+ secret_id = "github-token" ,
1556 replication = {
1657 "user_managed" : {
1758 "replicas" : [{ "location" : LOCATION }]
1859 }
19- }
60+ },
61+ opts = pulumi .ResourceOptions (
62+ depends_on = [secretmanager_service ]
63+ )
2064)
2165
22- # Set up a service account that has access to the secret, for the Function to use
23- service_account = gcp .serviceaccount .Account ("service-account" ,
24- account_id = "telegram-bot-service-account" ,
25- display_name = "Telegram Bot Service Account" )
26-
27- secret_access = gcp .secretmanager .SecretIamMember ("secret-access" ,
28- secret_id = telegram_bot_token .id ,
66+ github_connection_service_account_secret_access = gcp .secretmanager .SecretIamMember ("github-connection-service-account-secret-access" ,
67+ project = project_id .id ,
68+ secret_id = github_token_secret .id ,
2969 role = "roles/secretmanager.secretAccessor" ,
30- member = service_account .email .apply (lambda email : f"serviceAccount:{ email } " )
70+ member = pulumi .Output .concat (
71+ "serviceAccount:service-" ,
72+ project .number ,
73+ "@gcp-sa-cloudbuild.iam.gserviceaccount.com"
74+ ),
75+ opts = pulumi .ResourceOptions (
76+ depends_on = [cloudbuild_service ]
77+ )
3178)
3279
80+ github_connection = gcp .cloudbuildv2 .Connection ("github-connection" ,
81+ project = project_id .id ,
82+ name = "github-connection" ,
83+ location = LOCATION ,
84+ github_config = {
85+ "app_installation_id" : 30357801 ,
86+ "authorizer_credential" : {
87+ "oauth_token_secret_version" : github_token_secret .name .apply (lambda name : f"{ name } /versions/latest" )
88+ }
89+ },
90+ opts = pulumi .ResourceOptions (
91+ depends_on = [github_connection_service_account_secret_access ]
92+ )
93+ )
3394
34- # Set up the source code
35- source_bucket = gcp .storage .Bucket ("source-bucket" ,
95+ github_repository = gcp .cloudbuildv2 .Repository ("github-repository" ,
96+ project = project_id .id ,
97+ name = "telegram-bot" ,
3698 location = LOCATION ,
37- name = f"{ PROJECT_ID } -source-bucket" ,
99+ parent_connection = github_connection .name ,
100+ remote_uri = "https://github.com/osakunta/telegram-bot.git" ,
38101)
39102
40- source_asset = pulumi .AssetArchive ({
41- "telegram_bot" : pulumi .FileArchive ("../telegram_bot" ),
42- "main.py" : pulumi .FileAsset ("../main.py" ),
43- "requirements.txt" : pulumi .FileAsset ("../requirements.txt" )
44- })
45- source_object = gcp .storage .BucketObject ("source-object" ,
46- bucket = source_bucket .name ,
47- name = "telegram-bot-source" ,
48- source = source_asset
103+ # --- Set up CI/CD ---
104+
105+ cicd_service_account = utils .service_account_with_roles (
106+ "cicd-service-account" ,
107+ [
108+ "roles/logging.logWriter" ,
109+ "roles/cloudfunctions.developer" ,
110+ "roles/iam.serviceAccountUser" ,
111+ "roles/storage.objectViewer" ,
112+ "roles/artifactregistry.writer"
113+ ],
114+ project = project_id .id ,
115+ account_id = "cicd-service-account" ,
116+ display_name = "CICD Service Account"
49117)
50118
51- # Set up the Function, which handles the requests
52- function = gcp . cloudfunctionsv2 . Function ( "function " ,
53- location = LOCATION ,
54- name = "telegram-bot-function" ,
55- description = "Cloud Run Function for handling telegram bot requests " ,
56- build_config = {
57- "runtime" : "python313" ,
58- "entryPoint" : "telegram_bot" ,
59- "source" : {
60- "storage_source" : {
61- "bucket" : source_bucket . name ,
62- "object" : source_object . name ,
63- "generation " : source_object . generation
64- }
119+ runtime_service_account = utils . service_account_with_roles (
120+ "runtime-service-account " ,
121+ [ "roles/iam.serviceAccountUser" ] ,
122+ project = project_id . id ,
123+ account_id = "runtime-service-account " ,
124+ display_name = "Function Runtime Service Account"
125+ )
126+
127+ telegram_bot_token = gcp . secretmanager . Secret ( "telegram-bot-token" ,
128+ project = project_id . id ,
129+ secret_id = "telegram-bot-token" ,
130+ replication = {
131+ "user_managed " : {
132+ "replicas" : [{ "location" : LOCATION }]
65133 }
66- },
67- service_config = {
68- "availableMemory" : "128Mi" ,
69- "maxInstanceCount" : 1 , # No need for more than one instance
70- "minInstanceCount" : 0 , # Important to allow scale-to-zero, to save costs
71- "service_account_email" : service_account .email ,
72- "ingressSettings" : "ALLOW_ALL" ,
73- "secret_environment_variables" : [{
74- "key" : "TOKEN" ,
75- "project_id" : PROJECT_ID ,
76- "secret" : telegram_bot_token .secret_id ,
77- "version" : "latest"
78- }],
79- }
134+ },
135+ opts = pulumi .ResourceOptions (
136+ depends_on = [secretmanager_service ]
137+ )
80138)
81139
82- # Finally, set an IAM policy to allow unauthenticated people (anyone) to invoke the function
83- # this has to be cloudrun.ServiceIamMember instead of cloudfunctions.FunctionIamMember
84- # because the function is v2
85- function_public_iam = gcp .cloudrunv2 .ServiceIamMember ("function-public-iam" ,
140+ telegram_bot_token_secret_access = gcp .secretmanager .SecretIamMember ("telegram-bot-token-secret-access" ,
141+ project = project_id .id ,
142+ secret_id = telegram_bot_token .id ,
143+ role = "roles/secretmanager.secretAccessor" ,
144+ member = runtime_service_account .member ,
145+ )
146+
147+ deploy_trigger = gcp .cloudbuild .Trigger ("deploy-trigger" ,
148+ project = project_id .id ,
149+ name = "deploy" ,
86150 location = LOCATION ,
87- name = function .name ,
88- role = "roles/run.invoker" ,
89- member = "allUsers"
151+ service_account = cicd_service_account .id ,
152+ repository_event_config = {
153+ "repository" : github_repository .id ,
154+ "push" : {
155+ "branch" : f"^{ STACK_NAME } $" ,
156+ }
157+ },
158+ build = {
159+ "steps" : [
160+ {
161+ "name" : "gcr.io/cloud-builders/gcloud" ,
162+ "args" : [
163+ "functions" , "deploy" , "telegram-bot" ,
164+ "--region" , LOCATION ,
165+ "--runtime" , "python313" ,
166+ "--entry-point" , "telegram_bot" ,
167+ "--trigger-http" ,
168+ "--allow-unauthenticated" ,
169+ "--timeout" , "5s" ,
170+ "--gen2" ,
171+ "--max-instances" , "1" ,
172+ "--min-instances" , "0" ,
173+ "--memory" , "128Mi" ,
174+ "--set-secrets" , telegram_bot_token .name .apply (lambda name : f"TOKEN={ name } /versions/latest" ),
175+ "--source" , "." ,
176+ "--run-service-account" , runtime_service_account .email ,
177+ "--build-service-account" , cicd_service_account .id ,
178+ ],
179+ }
180+ ],
181+ "options" : {
182+ "logging" : "CLOUD_LOGGING_ONLY"
183+ }
184+ },
185+ opts = pulumi .ResourceOptions (
186+ depends_on = [ cloudrun_service , cloudfunctions_service , cloudresourcemanager_service ]
187+ )
90188)
0 commit comments