본문 바로가기
앱 제작/키워드 알림 앱

헤로쿠(heroku)에서 파이어베이스를 credentials JSON 파일 없이 사용하기

by Kim Juhwan 2021. 1. 20.

 

 


 

1. 첫 번째 삽질

지금까지 개인 노트북을 개인 서버로 사용하고 있었는데

아무래도 장기간 켜 두어야 하다 보니 부담이 되었다.

그러다가 heroku에 대해 알게 되었고 서버를 옮기려고 하는데 문제가 생겼다.

파이어 베이스를 사용하려면 키값이나 노출되어서는 안 되는 값들을 JSON파일로 저장해놓고 사용해야 한다는 것이다.

(JSON 파일은 인증에 사용된다)

 

 

Heroku file upload

I have a local file download, which gets triggered in the following fashion. panelBody.append('

') function downloadCsv(...

stackoverflow.com

근데 문제는 heroku에 파일을 업로드할 수 없다는 것이였다.

다른 DB 서비스를 이용해 파일을 저장하라는 답변들만 찾을 수 있었다.

 

나는 기존에 파이어 베이스를 사용하고 있었으므로 이걸 사용하면 되나? 싶었지만

파이어 베이스를 사용하려면 JSON 파일이 필요하고 -> JSON 파일을 업로드하려면 파이어 베이스가 필요하고 (아니 근데 애초에 JSON 파일 형태로 업로드가 되나?) -> 파이어 베이스가 필요하고 -> JSON을 업로드해야 하고 -> 파이ㅇ...

아무튼 그래서 JSON 파일을 저장할 다른 DB 서비스도 같이 이용해야 하나 싶었는데

뭔가 해결 방법이 있지 않을까 해서 더 알아보았다.

 

 

 

2. 두 번째 삽질

cred = credentials.Certificate(JSON 파일을 입력하는 곳)
firebase_admin.initialize_app(cred,{
    'databaseURL' : 'url 입력하는 곳'
})

인증하는 부분의 코드를 보면 JSON 파일을 입력하는 곳이 있다.

원래 여기에 JSON 파일이 저장된 경로를 입력해줬는데

JSON을 코드상에서 직접 만들어서 넣으면 되지 않을까?라는 생각이 들었다.

 

cred_json = OrderedDict() #해쉬맵 구조 사용
cred_json["type"] = "service_account"
cred_json["project_id"] = "push......"
cred_json["private_key_id"] = "a42b2......"
cred_json["private_key"] = "L5ta0......"
cred_json["client_email"] = "firebase-adminsdk......"
cred_json["client_id"] = "1138......"
cred_json["auth_uri"] = "https://......"
cred_json["token_uri"] = "https://......"
cred_json["auth_provider_x509_cert_url"] = "https://......"
cred_json["client_x509_cert_url"] = "https://......"
JSON = json.dumps(cred_json) #python 객체 -> json 객체

cred = credentials.Certificate(JSON)
firebase_admin.initialize_app(cred,{
    'databaseURL' : 'https://......'
})

파이썬을 공부해본 적이 없어서 잘 모르지만

OrderedDict은 해쉬 맵 구조를 사용하기 위해 사용했고

dumps는 python 객체를 json 객체로 변환하기 위해 사용했다.

 

 

에러가 떴다.

그랬더니 위와 같은 에러가 떴다.

파일 형태이던지, 경로 형태여야 한다는 것 같았다.

하... 이 방법도 안 되는 건가..?

 

 

 

3. 세 번째 삽질

 

How to Set Google Firebase Credentials not with Json file but with python dict?

I have been spending a few hours trying to set my Google Firebase credentials without using a Json file path as recommended in setup guide and have no luck. What I am trying to do I store the con...

stackoverflow.com

나랑 똑같은 짓거리(?)를 하고 싶어 하는 사람이 있었고 답변들을 참고해서

코드 한 줄을 추가해봤다.

 

cred_json = OrderedDict()
cred_json["type"] = "service_account"
cred_json["project_id"] = "push......"
cred_json["private_key_id"] = "a42b2......"
cred_json["private_key"] = "L5ta0......"
cred_json["client_email"] = "firebase-adminsdk......"
cred_json["client_id"] = "1138......"
cred_json["auth_uri"] = "https://......"
cred_json["token_uri"] = "https://......"
cred_json["auth_provider_x509_cert_url"] = "https://......"
cred_json["client_x509_cert_url"] = "https://......"
JSON = json.dumps(cred_json)
JSON = json.loads(JSON) #json 객체 -> python 객체

cred = credentials.Certificate(JSON)
firebase_admin.initialize_app(cred,{
    'databaseURL' : 'https://......'
})

이렇게 했더니 드디어 파이어 베이스 인증이 가능해졌다!!

해쉬 맵 구조를 json으로 만들기 위해 dumps를 썼다가

Certificate에는 다시 python객체 형태로 값을 줘야 해서 loads를 사용해야 하는 듯했다.

드디어 성공 ㅠㅠㅠ

 

import os

cred_json = OrderedDict()
cred_json["type"] = os.environ["type"] # 이렇게 값을 숨겨주는 게 좋다.
cred_json["project_id"] =
cred_json["private_key_id"] =
cred_json["private_key"] =
cred_json["client_email"] =
cred_json["client_id"] =
cred_json["auth_uri"] =
cred_json["token_uri"] =
cred_json["auth_provider_x509_cert_url"] =
cred_json["client_x509_cert_url"] =

JSON = json.dumps(cred_json)
JSON = json.loads(JSON) #json 객체 -> python 객체

cred = credentials.Certificate(JSON)
firebase_admin.initialize_app(cred,{
    'databaseURL' : os.environ["databaseURL"] # 코드에 직접 값이 노출되지 않게 하자.
})

예전에 인터넷에서 그런 글을 본 적이 있다.

면접자들이 진행했던 프로젝트랍시고 보여주는 걸 보면

키값도 코드상에 그대로 노출하고 인터넷에 떠돌아다니는 코드 몇 개 긁어와서 사용한다고...

이 글이 그 뒤로 계속 머릿속에 맴돌아서 방법을 찾아보았다.

 

내가 사용하는 heroku 서버는 깃허브와 연동이 가능하다.

그래서 private으로 소스를 올려서 프로그램을 실행하면 코드상에 키값이 남아도 문제가 없으나

좀 더 확실하게 해보고자 했다.

그래서 환경변수에 값을 저장하고 불러오는 방법을 선택했다.

코드는 위와 같이 작성하고 heroku 설정에 들어가서 값을 넣어주면 키 값이 노출되지 않는다.

 

 

 

4. 네 번째 삽질

파이참에서는 코드가 분명히 문제없이 돌아갔는데

헤로쿠에 코드를 올려서 실행을 하면 위와 같은 문제가 생겼다.

Failed to initialize a certificate credential. Caused by: "No key could be detected." ...

나는 키 값을 분명히 잘 적어줬는데 없다고 하니 미치고 팔짝 뛸 노릇

 

 

Failed to initialize a certificate credential. Caused by: "No key could be detected." · Issue #188 · firebase/firebase-admin-p

Operating System version: Ubuntu 14 (Windows 10 Bash) Firebase SDK version: 2.12.0 Firebase Product: database Library: Python 2.7.15 I've installed Cloud Firestore Python library with following...

github.com

검색을 하다가 그 이유를 찾아냈다.

private key에 엔터를 의미하는 '\n'이 들어가는데

이게 헤로쿠에서는 '\\n'으로 변환해서 들어가기 때문에 키값을 인식하지 못했던 것.

(꼭 헤로쿠만의 문제가 아니라 일부 플랫폼들이 그렇다고 한다)

 

import os

cred_json = OrderedDict()
cred_json["type"] = 
cred_json["project_id"] =
cred_json["private_key_id"] =
cred_json["private_key"] = os.environ["private_key"].replace('\\n', '\n') # 엔터 문자를 변환해서 사용
cred_json["client_email"] =
cred_json["client_id"] =
cred_json["auth_uri"] =
cred_json["token_uri"] =
cred_json["auth_provider_x509_cert_url"] =
cred_json["client_x509_cert_url"] =

그래서 이렇게 replace를 이용해서 문자를 변환해주면 잘 돌아간다.

다른 키 값에는 엔터가 들어가지 않아서 private key만 이렇게 처리해주면 된다.

후! 드디어 지인짜 성공!

 

 


 

 

Python Version : 3.8

Pycharm Version : 2020.2.2 (Community Edition)

firebase_admin 4.5.0

heroku

반응형

댓글