1# frozen_string_literal: true 2 3module Gitlab 4 module Ci 5 class Jwt 6 NOT_BEFORE_TIME = 5 7 DEFAULT_EXPIRE_TIME = 60 * 5 8 9 NoSigningKeyError = Class.new(StandardError) 10 11 def self.for_build(build) 12 self.new(build, ttl: build.metadata_timeout).encoded 13 end 14 15 def initialize(build, ttl: nil) 16 @build = build 17 @ttl = ttl 18 end 19 20 def payload 21 custom_claims.merge(reserved_claims) 22 end 23 24 def encoded 25 headers = { kid: kid, typ: 'JWT' } 26 27 JWT.encode(payload, key, 'RS256', headers) 28 end 29 30 private 31 32 attr_reader :build, :ttl 33 34 def reserved_claims 35 now = Time.now.to_i 36 37 { 38 jti: SecureRandom.uuid, 39 iss: Settings.gitlab.host, 40 iat: now, 41 nbf: now - NOT_BEFORE_TIME, 42 exp: now + (ttl || DEFAULT_EXPIRE_TIME), 43 sub: "job_#{build.id}" 44 } 45 end 46 47 def custom_claims 48 fields = { 49 namespace_id: namespace.id.to_s, 50 namespace_path: namespace.full_path, 51 project_id: project.id.to_s, 52 project_path: project.full_path, 53 user_id: user&.id.to_s, 54 user_login: user&.username, 55 user_email: user&.email, 56 pipeline_id: build.pipeline.id.to_s, 57 pipeline_source: build.pipeline.source.to_s, 58 job_id: build.id.to_s, 59 ref: source_ref, 60 ref_type: ref_type, 61 ref_protected: build.protected.to_s 62 } 63 64 if environment.present? 65 fields.merge!( 66 environment: environment.name, 67 environment_protected: environment_protected?.to_s 68 ) 69 end 70 71 fields 72 end 73 74 def key 75 @key ||= begin 76 key_data = if Feature.enabled?(:ci_jwt_signing_key, build.project, default_enabled: true) 77 Gitlab::CurrentSettings.ci_jwt_signing_key 78 else 79 Rails.application.secrets.openid_connect_signing_key 80 end 81 82 raise NoSigningKeyError unless key_data 83 84 OpenSSL::PKey::RSA.new(key_data) 85 end 86 end 87 88 def public_key 89 key.public_key 90 end 91 92 def kid 93 public_key.to_jwk[:kid] 94 end 95 96 def project 97 build.project 98 end 99 100 def namespace 101 project.namespace 102 end 103 104 def user 105 build.user 106 end 107 108 def source_ref 109 build.pipeline.source_ref 110 end 111 112 def ref_type 113 ::Ci::BuildRunnerPresenter.new(build).ref_type 114 end 115 116 def environment 117 build.persisted_environment 118 end 119 120 def environment_protected? 121 false # Overridden in EE 122 end 123 end 124 end 125end 126 127Gitlab::Ci::Jwt.prepend_mod_with('Gitlab::Ci::Jwt') 128