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