Exemple #1
0
Fichier : api.py Projet : esk8s/esk
    def create_secret(self, secret: AWSSecret):
        '''
      Process the creation of an awssecrets resource
    '''

        try:
            self.__client.create_secret(
                Name=secret.get_path(),
                SecretBinary=json.dumps(
                    secret.get_creation_values()).encode('utf-8'))
        except self.__client.exceptions.ResourceExistsException:
            raise ESKException(409, "Path already exists")
        except Exception as e:
            raise ESKException(500, e.message)
Exemple #2
0
  def update_secret(self, old_secret: ExternalSecret, new_secret: ExternalSecret):
    '''
      Process the update of an externalsecrets resource
    '''

    backend_client = self.__controller.get_backend_client(old_secret.get_backend())

    # when creation happens, this handler will skip updating.
    if old_secret.get_path() is None:
      return True

    self.__controller.can_access_secret(old_secret)
    self.__controller.can_access_secret(new_secret)

    __trigger_value_change = False
    old_values = old_secret.get_raw_values()
    new_values = new_secret.get_raw_values()
    real_values = None

    for k, v in new_values.items():
      if old_values.get(k) == v:
        if real_values is None:
          real_values = backend_client.get_secret(old_secret)
          if real_values is None:
            raise ESKException(500, f"Values retrieved for path { old_secret.get_path() } are None")
        
        new_values[k] = real_values[k]

    new_secret.set_real_values(new_values)
    backend_client.update_secret(__trigger_value_change, old_secret, new_secret)

    return new_secret
Exemple #3
0
def get_vault_client() -> hvac.Client:
    addr = os.environ['VAULT_ADDR']
    logger.debug(f"Setting up vault connection to { addr }")

    token = os.environ.get('VAULT_TOKEN') or "/vault/secrets/token"
    if token is None:
        raise Exception(
            "Please specify a path to the vault token either via --token or $VAULT_TOKEN"
        )

    with open(token, "r") as f:
        token = f.read().rstrip()

    client = hvac.Client(url=addr, token=token)
    if client.is_authenticated():
        return client
    else:
        raise ESKException(500, "Authentication to vault unsuccessful")


# def __login_approle(self):
#   pass

# def __login_kubernetes(self):
#   pass

# def __login_token(self):
#   pass
Exemple #4
0
Fichier : api.py Projet : esk8s/esk
    def grant_access(self, bind: SecretBinding):
        role, role_binding = bind.to_k8s_resources()

        try:
            self.__rbac_api.create_namespaced_role(bind.get_namespace(), role)
            self.__rbac_api.create_namespaced_role_binding(
                bind.get_namespace(), role_binding)
        except kubernetes.client.exceptions.ApiException as e:
            raise ESKException(e.status, e.reason)
Exemple #5
0
Fichier : api.py Projet : esk8s/esk
    def revoke_access(self, bind: SecretBinding):
        try:
            self.__rbac_api.delete_namespaced_role(bind.get_name(),
                                                   bind.get_namespace())
        except kubernetes.client.ApiException as e:
            if e.status != 404:
                raise ESKException(e.status, e.reason)
            else:
                logger.debug(f"Role { bind.get_name() } did not exist, skip.")

        try:
            self.__rbac_api.delete_namespaced_role_binding(
                bind.get_name(), bind.get_namespace())
        except kubernetes.client.ApiException as e:
            if e.status != 404:
                raise ESKException(e.status, e.reason)
            else:
                logger.debug(
                    f"Role binding { bind.get_name() } did not exist, skip.")
Exemple #6
0
Fichier : api.py Projet : esk8s/esk
 def list_crd(self, crd, namespace):
     try:
         return self.__crd_api.list_namespaced_custom_object(
             'esk.io',
             'v1alpha1',
             namespace,
             crd,
         ).get('items')
     except kubernetes.client.exceptions.ApiException as e:
         raise ESKException(e.status, e.reason)
Exemple #7
0
    def get_secret(self, secret: VaultSecret):
        mount_point, path = secret.get_mount_point_and_path()

        try:
            values = self.__client.secrets.kv.v2.read_secret_version(
                path, mount_point=mount_point)["data"]["data"]
        except hvac.exceptions.InvalidPath:
            raise ESKException(404, "Secret not found in backend")

        logger.debug(f"Found secret { path } in vault.")
        return values
Exemple #8
0
  def __init__(self, name, namespace, backend, placeholder, path, values):
    self.__name = name
    self.__namespace = namespace
    self.__backend = backend

    if not self.__name:
      raise ESKException(400, "Name cannot be empty")

    if not self.__namespace:
      raise ESKException(400, "Namespace cannot be empty")

    self.__placeholder = placeholder
    self.__values = values if values is not None else {}
    self.__real_values = None
    self.__annotations = None
    self.__masked_values = {}
    self.__set_masked_values()

    if path is None:
      self.__path = f"{ self.__namespace }-{ self.__name }"
    else:
      self.__path = path
Exemple #9
0
    def can_access_secret(self, secret: ExternalSecret):
        allowed = False

        for spec in self.__clients.get('k8s').list_crd('secretpolicies',
                                                       secret.get_namespace()):
            allowed = SecretPolicy(
                spec.get('name'), spec.get('namespace'), spec.get('allow'),
                spec.get('reject')).check_path_allowed(secret)

            if allowed:
                break

        if not self.__allow_by_default and not allowed:
            raise ESKException(403, "Path not allowed.")
Exemple #10
0
Fichier : api.py Projet : esk8s/esk
    def delete_secret(self, secret: AWSSecret):
        '''
      Process the deletion of an awssecrets resource
    '''

        try:
            if secret.should_delete_instantly():
                self.__client.delete_secret(ForceDeleteWithoutRecovery=True,
                                            SecretId=secret.get_path())
            else:
                self.__client.delete_secret(
                    RecoveryWindowInDays=secret.get_recovery_days(),
                    SecretId=secret.get_path())
        except self.__client.exceptions.InvalidRequestException as e:
            raise ESKException(500, e.message)
Exemple #11
0
  def get_secret_spec(self, name: str, namespace: str):
    '''
      Get the CRD resource from kubernetes
    '''

    api_instance = kubernetes.client.CustomObjectsApi(self.__controller.get_backend_client('k8s'))

    try:
      return api_instance.api_instance.get_namespaced_custom_object(
        'esk.io',
        'v1alpha1',
        namespace,
        f"externalsecrets",
        name
      )
    except kubernetes.client.exceptions.ApiException:
      raise ESKException(404, f"Secret { namespace }/{ name } could not be found")
Exemple #12
0
Fichier : api.py Projet : esk8s/esk
    def create_secret(self, secret: GCPSecret):
        '''
      Process the creation of an gcpsecrets resource
    '''

        # Build a dict of settings for the secret
        secret_metadata = {'replication': secret.get_replication()}

        # Create the secret
        try:
            self.__client.create_secret(
                secret_id=secret.get_path(),
                parent=f"projects/{ self.__project_id }",
                secret=secret_metadata)
        except api_core.exceptions.AlreadyExists as e:
            raise ESKException(409, "Path already exists")

        self.__add_secret_version(secret)
Exemple #13
0
    def create_secret(self, secret: VaultSecret):
        '''
      Process the creation of a vaultsecrets resource
    '''

        mount_point, path = secret.get_mount_point_and_path()

        try:
            self.__client.secrets.kv.v2.create_or_update_secret(
                path,
                secret=secret.get_creation_values(),
                mount_point=mount_point,
                cas=0)
        except hvac.exceptions.InvalidRequest as e:
            raise ESKException(409, "Path already exists")

        logger.debug(f"Created secret { mount_point }/{ path } in vault.")

        # policy_name = f"{ namespace }-{ name }"

        # self.__client.sys.create_or_update_policy(policy_name, f"path \"{ mount_point }/{ path }\" {{\n  capabilities = [\"read\"]\n}}\n")
        # logger.debug(f"Created policy {policy_name}")

        return f"{ mount_point }/{ path }"
Exemple #14
0
from controller.main import get_controllers
from controller.exceptions import ESKException
from injector.webhook import mutate
from injector.processor import ESKProcessor

app = Flask(__name__)
app.logger.setLevel(logging.DEBUG)

s_controller, sb_controller = get_controllers()
processor = ESKProcessor(s_controller)

processor_addr = environ.get('PROCESSOR_ADDR')
init_image = environ.get('INIT_IMAGE')

if processor_addr is None:
    raise ESKException(500, "Processor addr is invalid.")

if init_image is None:
    raise ESKException(500, "Init image is invalid.")


@app.route('/mutate', methods=['POST'])
def mutate_webhook():
    allowed, patch = mutate(sb_controller, init_image, processor_addr,
                            request.json["request"])

    admission_response = {
        "allowed": allowed,
        "uid": request.json["request"]["uid"],
        "patch": patch,
        "patchtype": "JSONPatch"
Exemple #15
0
  def check_can_create(self):
    if not self.__path:
      raise ESKException(500, "Secrets require a valid path")

    if not isinstance(self.__values, dict) or len(self.__values.keys()) == 0:
      raise ESKException(500, f"Failed to create: values not a valid dict: { self.__values}")