Class: Hippo::Secret

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/hippo/secret.rb

Constant Summary collapse

HEADER =
[
  '# This file is encrypted and managed by Hippo.',
  '# Use `hippo secret [stage] [name]` to make changes to it.',
  '#',
  '# Note: this cannot be applied directly to your Kubernetes server because',
  '# HippoEncryptedSecret is not a valid object. It will be automatically ',
  '# converted to a Secret when it is applied by Hippo.'
].join("\n")

Instance Method Summary collapse

Methods included from Util

#load_yaml_from_data, #load_yaml_from_directory, #load_yaml_from_path, #open_in_editor

Constructor Details

#initialize(manager, name) ⇒ Secret

Returns a new instance of Secret.



21
22
23
24
# File 'lib/hippo/secret.rb', line 21

def initialize(manager, name)
  @manager = manager
  @name = name
end

Instance Method Details

#createvoid

This method returns an undefined value.

Create a new templated encrypted secret with the given name



111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/hippo/secret.rb', line 111

def create
  template = {
    'apiVersion' => 'v1',
    'kind' => 'HippoEncryptedSecret',
    'metadata' => {
      'name' => @name
    },
    'data' => {
      'example' => @manager.encrypt('This is an example secret!')
    }
  }
  write([template])
end

#editvoid

This method returns an undefined value.

Edit a secret file by opening an editor and allow changes to be made. When the editor completes, finish by writing the file back to the disk.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/hippo/secret.rb', line 67

def edit
  return unless exists?

  # Obtain a list of parts and map them to the name of the secret
  # in the file.
  original_decrypted_part_data = parse_parts(load_yaml_from_path(path), :decrypt)
  original_encrypted_part_data = load_yaml_from_path(path).each_with_object({}) do |part, hash|
    next if part.nil? || part.empty?

    hash[part.dig('metadata', 'name')] = part['data']
  end
  original_part_data = original_decrypted_part_data.each_with_object({}) do |part, hash|
    name = part.dig('metadata', 'name')
    enc = original_encrypted_part_data[name]
    next if enc.nil?

    hash[part.dig('metadata', 'name')] = part['data'].each_with_object({}) do |(key, value), hash2|
      hash2[key] = [value, enc[key]]
    end
  end

  # Open the editor and gather what the user provides.
  saved_contents = open_in_editor("secret-#{@name}", to_editable_yaml)

  # This saved contents should now be validated to ensure it is valid
  # YAML and, if so, it should be encrypted and then saved into the
  # secret file as needed.
  begin
    yaml_parts = load_yaml_from_data(saved_contents)
    parts = parse_parts(yaml_parts, :encrypt, original_part_data)
    write(parts)
  rescue StandardError => e
    raise
    puts "An error occurred parsing your file: #{e.message}"
    saved_contents = open_in_editor("secret-#{@name}", saved_contents)
    retry
  end

  puts "#{@name} secret has been editted"
end

#exists?Boolean

Does the secret file currently exist on the file system?

Returns:

  • (Boolean)


36
37
38
# File 'lib/hippo/secret.rb', line 36

def exists?
  File.file?(path)
end

#pathString

Return the path to the stored encrypted secret file

Returns:

  • (String)


29
30
31
# File 'lib/hippo/secret.rb', line 29

def path
  File.join(@manager.recipe.root, 'secrets', @manager.stage.name, "#{@name}.yaml")
end

#to_editable_yamlString

Return the secret file as it should be displayed for editting

Returns:

  • (String)


59
60
61
# File 'lib/hippo/secret.rb', line 59

def to_editable_yaml
  decrypted_parts.map { |p| p.hash.to_yaml } .join("---\n")
end

#to_secret_yamlString

Return the secret file as it should be applied to Kubernetes.

Returns:

  • (String)


43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/hippo/secret.rb', line 43

def to_secret_yaml
  decrypted_parts.map do |part, _array|
    part['kind'] = 'Secret'
    part['metadata'] ||= {}
    part['metadata']['namespace'] = @manager.stage.namespace

    part['data'].each do |key, value|
      part['data'][key] = Base64.encode64(value).gsub("\n", '').strip
    end
    part
  end.map { |p| p.hash.to_yaml } .join("---\n")
end