mirror of https://github.com/veops/cmdb.git
feat: add inner password storage
This commit is contained in:
parent
27a1c75a25
commit
e725fb8473
|
@ -18,6 +18,7 @@ from flask.json.provider import DefaultJSONProvider
|
||||||
|
|
||||||
import api.views.entry
|
import api.views.entry
|
||||||
from api.extensions import (bcrypt, cache, celery, cors, db, es, login_manager, migrate, rd)
|
from api.extensions import (bcrypt, cache, celery, cors, db, es, login_manager, migrate, rd)
|
||||||
|
from api.extensions import inner_secrets
|
||||||
from api.flask_cas import CAS
|
from api.flask_cas import CAS
|
||||||
from api.models.acl import User
|
from api.models.acl import User
|
||||||
|
|
||||||
|
@ -125,6 +126,7 @@ def register_extensions(app):
|
||||||
|
|
||||||
app.config.update(app.config.get("CELERY"))
|
app.config.update(app.config.get("CELERY"))
|
||||||
celery.conf.update(app.config)
|
celery.conf.update(app.config)
|
||||||
|
inner_secrets.init_app(app)
|
||||||
|
|
||||||
|
|
||||||
def register_blueprints(app):
|
def register_blueprints(app):
|
||||||
|
|
|
@ -12,6 +12,8 @@ from flask_sqlalchemy import SQLAlchemy
|
||||||
from api.lib.utils import ESHandler
|
from api.lib.utils import ESHandler
|
||||||
from api.lib.utils import RedisHandler
|
from api.lib.utils import RedisHandler
|
||||||
|
|
||||||
|
from api.lib.secrets.inner import KeyManage
|
||||||
|
|
||||||
bcrypt = Bcrypt()
|
bcrypt = Bcrypt()
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
db = SQLAlchemy(session_options={"autoflush": False})
|
db = SQLAlchemy(session_options={"autoflush": False})
|
||||||
|
@ -21,3 +23,4 @@ celery = Celery()
|
||||||
cors = CORS(supports_credentials=True)
|
cors = CORS(supports_credentials=True)
|
||||||
rd = RedisHandler()
|
rd = RedisHandler()
|
||||||
es = ESHandler()
|
es = ESHandler()
|
||||||
|
inner_secrets = KeyManage()
|
||||||
|
|
|
@ -22,7 +22,6 @@ from flask import current_app
|
||||||
global_iv_length = 16
|
global_iv_length = 16
|
||||||
global_key_shares = 5 # Number of generated key shares
|
global_key_shares = 5 # Number of generated key shares
|
||||||
global_key_threshold = 3 # Minimum number of shares required to rebuild the key
|
global_key_threshold = 3 # Minimum number of shares required to rebuild the key
|
||||||
global_shares = []
|
|
||||||
|
|
||||||
backend_root_key_name = "root_key"
|
backend_root_key_name = "root_key"
|
||||||
backend_encrypt_key_name = "encrypt_key"
|
backend_encrypt_key_name = "encrypt_key"
|
||||||
|
@ -30,7 +29,6 @@ backend_root_key_salt_name = "root_key_salt"
|
||||||
backend_encrypt_key_salt_name = "encrypt_key_salt"
|
backend_encrypt_key_salt_name = "encrypt_key_salt"
|
||||||
success = "success"
|
success = "success"
|
||||||
seal_status = True
|
seal_status = True
|
||||||
cache = {}
|
|
||||||
|
|
||||||
|
|
||||||
def string_to_bytes(value):
|
def string_to_bytes(value):
|
||||||
|
@ -43,27 +41,9 @@ def string_to_bytes(value):
|
||||||
return byte_string
|
return byte_string
|
||||||
|
|
||||||
|
|
||||||
class CacheBackend:
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, key):
|
|
||||||
global cache
|
|
||||||
return cache.get(key)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def add(cls, key, value):
|
|
||||||
cache[key] = value
|
|
||||||
return success, True
|
|
||||||
|
|
||||||
|
|
||||||
class Backend:
|
class Backend:
|
||||||
def __init__(self, backend=None):
|
def __init__(self, backend=None):
|
||||||
if not backend:
|
self.backend = backend
|
||||||
self.backend = CacheBackend
|
|
||||||
else:
|
|
||||||
self.backend = backend
|
|
||||||
|
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
return self.backend.get(key)
|
return self.backend.get(key)
|
||||||
|
@ -80,6 +60,9 @@ class KeyManage:
|
||||||
if backend:
|
if backend:
|
||||||
self.backend = Backend(backend)
|
self.backend = Backend(backend)
|
||||||
|
|
||||||
|
def init_app(self, app):
|
||||||
|
self.auto_unseal()
|
||||||
|
|
||||||
def hash_root_key(self, value):
|
def hash_root_key(self, value):
|
||||||
algorithm = hashes.SHA256()
|
algorithm = hashes.SHA256()
|
||||||
salt = self.backend.get(backend_root_key_salt_name)
|
salt = self.backend.get(backend_root_key_salt_name)
|
||||||
|
@ -166,18 +149,19 @@ class KeyManage:
|
||||||
"message": "current status is unseal, skip",
|
"message": "current status is unseal, skip",
|
||||||
"status": "skip"
|
"status": "skip"
|
||||||
}
|
}
|
||||||
global global_shares
|
|
||||||
try:
|
try:
|
||||||
t = [i for i in b64decode(key)]
|
t = [i for i in b64decode(key)]
|
||||||
v = (int("".join([chr(i) for i in t[-2:]])), bytes(t[:-2]))
|
v = (int("".join([chr(i) for i in t[-2:]])), bytes(t[:-2]))
|
||||||
if v not in global_shares:
|
shares = getattr(current_app, "secrets_shares", [])
|
||||||
global_shares.append(v)
|
if v not in shares:
|
||||||
if len(global_shares) >= global_key_threshold:
|
shares.append(v)
|
||||||
recovered_secret = Shamir.combine(global_shares[:global_key_threshold])
|
setattr(current_app, "secrets_shares", shares)
|
||||||
|
if len(shares) >= global_key_threshold:
|
||||||
|
recovered_secret = Shamir.combine(shares[:global_key_threshold])
|
||||||
return self.auth_root_secret(b64encode(recovered_secret))
|
return self.auth_root_secret(b64encode(recovered_secret))
|
||||||
else:
|
else:
|
||||||
return {
|
return {
|
||||||
"message": "waiting for inputting other unseal key {0}/{1}".format(len(global_shares),
|
"message": "waiting for inputting other unseal key {0}/{1}".format(len(shares),
|
||||||
global_key_threshold),
|
global_key_threshold),
|
||||||
"status": "waiting"
|
"status": "waiting"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue