{"id":5657,"date":"2020-10-12T07:56:25","date_gmt":"2020-10-12T04:56:25","guid":{"rendered":"https:\/\/www.almtoolbox.com\/blog_he\/?p=5657"},"modified":"2020-10-15T16:24:39","modified_gmt":"2020-10-15T13:24:39","slug":"how-to-use-gitlab-ci-and-vault","status":"publish","type":"post","link":"https:\/\/www.almtoolbox.com\/blog_he\/how-to-use-gitlab-ci-and-vault\/","title":{"rendered":"\u05d4\u05e1\u05d1\u05e8\u05d9\u05dd \u05d5\u05d4\u05d3\u05d2\u05de\u05d4 \u05d0\u05d9\u05da \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1- GitLab CI  \u05d9\u05d7\u05d3 \u05e2\u05dd Vault"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-5665\" src=\"https:\/\/www.almtoolbox.com\/blog_he\/wp-content\/uploads\/2020\/10\/gitlab-ci-vault.jpg\" alt=\"gitlab-ci-vault\" width=\"700\" height=\"352\" srcset=\"https:\/\/www.almtoolbox.com\/blog_he\/wp-content\/uploads\/2020\/10\/gitlab-ci-vault.jpg 1105w, https:\/\/www.almtoolbox.com\/blog_he\/wp-content\/uploads\/2020\/10\/gitlab-ci-vault-300x151.jpg 300w, https:\/\/www.almtoolbox.com\/blog_he\/wp-content\/uploads\/2020\/10\/gitlab-ci-vault-1024x514.jpg 1024w, https:\/\/www.almtoolbox.com\/blog_he\/wp-content\/uploads\/2020\/10\/gitlab-ci-vault-768x386.jpg 768w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>\u05d4\u05e2\u05dc\u05e0\u05d5 \u05dc\u05db\u05d0\u05df \u05e1\u05e8\u05d8\u05d5\u05df \u05d7\u05d3\u05e9 \u05d5\u05e9\u05d9\u05de\u05d5\u05e9\u05d9, \u05d4\u05db\u05d5\u05dc\u05dc \u05d4\u05e1\u05d1\u05e8\u05d9\u05dd \u05d5\u05d4\u05d3\u05d2\u05de\u05d4 (\u05d3\u05de\u05d5). \u05d4\u05d3\u05de\u05d5 \u05de\u05e6\u05d9\u05d2 \u05d0\u05d9\u05da \u05d0\u05e4\u05e9\u05e8 \u05dc\u05d7\u05d1\u05e8 \u05d1\u05d9\u05df GitLab CI\u00a0 \u05dc\u05d1\u05d9\u05df HashiCorp Vault \u05e2&quot;\u05de \u05dc\u05d7\u05e9\u05d5\u05e3 \u05d0\u05ea \u05d4\u05e1\u05d5\u05d3\u05d5\u05ea (secrets) \u05dc- GitLab runners .<br \/>\n\u05d4\u05d3\u05de\u05d5 \u05d2\u05dd \u05de\u05e6\u05d9\u05d2 \u05d0\u05d9\u05da \u05e1\u05d5\u05d3\u05d5\u05ea \u05d1\u05e1\u05d1\u05d9\u05d1\u05ea production \u05d9\u05db\u05d5\u05dc\u05d9\u05dd \u05dc\u05d4\u05d9\u05d5\u05ea \u05de\u05d5\u05d2\u05e0\u05d9\u05dd \u05de\u05e9\u05d9\u05de\u05d5\u05e9 \u05dc\u05d0 \u05e0\u05db\u05d5\u05df.<br \/>\n\u05d1\u05ea\u05d7\u05d9\u05dc\u05ea \u05d4\u05e1\u05e8\u05d8\u05d5\u05df \u05d9\u05e9 \u05db\u05de\u05d4 \u05d3\u05e7\u05d5\u05ea \u05e9\u05dc \u05e8\u05e7\u05e2 \u05d5\u05de\u05d1\u05d5\u05d0 \u05e2\u05dc Vault \u05d5\u05e2\u05dc GitLab CI .<\/p>\n<p>\u05d4\u05d4\u05d3\u05d2\u05de\u05d4 \u05de\u05ea\u05d7\u05d9\u05dc\u05d4 \u05d1\u05d3\u05e7\u05d4 6:39 .<\/p>\n<p>\u05dc\u05e0\u05d5\u05d7\u05d9\u05d5\u05ea\u05db\u05dd \u05d4\u05d5\u05e1\u05e4\u05e0\u05d5 \u05db\u05ea\u05d5\u05d1\u05d9\u05d5\u05ea \u05d5\u05d8\u05e7\u05e1\u05d8 (\u05ea\u05de\u05dc\u05d9\u05dc) \u05de\u05dc\u05d0 \u05d1\u05d4\u05de\u05e9\u05da.<\/p>\n<h2>\u05dc\u05e6\u05e4\u05d9\u05d9\u05d4:<\/h2>\n<p><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/q3wQ_zYOQaM\" width=\"700\" height=\"393.75\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><span data-mce-type=\"bookmark\" style=\"display: inline-block; width: 0px; overflow: hidden; line-height: 0;\" class=\"mce_SELRES_start\">\ufeff<\/span><\/iframe><\/p>\n<h3>\u05e7\u05d9\u05e9\u05d5\u05e8\u05d9\u05dd \u05e8\u05dc\u05d1\u05e0\u05d8\u05d9\u05dd:<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.almtoolbox.com\/il\/gitlab\" target=\"_blank\" rel=\"noopener noreferrer\">\u05d0\u05ea\u05e8 GitLab \u05d5- GitLab CI \u05d9\u05e9\u05e8\u05d0\u05dc<\/a> (\u05e2\u05d1\u05e8\u05d9\u05ea)<\/li>\n<li><a href=\"https:\/\/www.almtoolbox.com\/il\/vault\" target=\"_blank\" rel=\"noopener noreferrer\">\u05d0\u05ea\u05e8 Vault \u05d9\u05e9\u05e8\u05d0\u05dc<\/a> (\u05e2\u05d1\u05e8\u05d9\u05ea)<\/li>\n<\/ul>\n<h3 dir=\"ltr\">Transcription:<\/h3>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" dir=\"ltr\" tabindex=\"0\" role=\"button\">Good day,<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">My name is Michael Krakowski. I work as a solutions architect for GitLab.<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">Today I'd like to tell you why and how would you want to integrate HashiCorp Vault with GitLab.<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">Let's start with understanding what HashiCorp Vault is from an engineering perspective.<\/div>\n<div tabindex=\"0\" role=\"button\"><\/div>\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">Functionally it is a credential database it implements similar principle to the hardware security modules,<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">once used in the industry except it does in software,<\/div>\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">so you have storage containing the database and this storage can only be booted into the actual service by using an out of m keys available and once it is up and running it can be used to read write update and delete secrets.<\/div>\n<div tabindex=\"0\" role=\"button\"><\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">As simple as that interaction happens using API either directly or via GUI or the command line client (CLI).<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">this command line client is the same statically linked binary written in Go which is used to boot a server so as usual with go binaries it can run practically anywhere, and whenever you want to access the service you need to talk to one of the authentication services first in order to obtain a token which will then authorize all the requests to the service.<\/div>\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">Now where Vault really gets useful is infrastructure-specific back-ends.<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">They are modules implementing this functionality for various types of infrastructure which can be used interchangeably for example for AWS.<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">you can have a back end which defines credential but this credential is not a static one &#8211; it's a dynamically generated credential bound to specific AWS role, so every time you request it you get a different physical credential and Vault manages it meaning the credential has a limited time to live. It can be renewed or not it can be destroyed once it is not being used anymore, which limits the time of life of this credential and limits the risk of the actual leak of it.<\/div>\n<div tabindex=\"0\" role=\"button\"><\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">Now from our perspective what matters from the perspective of integration is that vault database is built as a tree-like structure so you have a configuration three and credentials live in the branches<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">and the way you manage access to that database is via policies which grant specific operations on specific branches<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">for example, ability to write to that credential or ability to read that credential or ability to destroy the credential now policies are gathered into roles which are essentially a group of policies and every single authentication request<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">uh to to to authentication services to generate token happens in the context of a given role so so token impersonates the role and then every request using this token is effectively authorized by vault to either conduct or not the operations requested from the perspective of GitLab the objective is of course to make those voltmeters credentials available to the runner so that you can have environment specific credentials stored in the database, they're not<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">managed within GitLab but GitLab can still request them and use them as needed the whole authentication concept is based on JSON web token which is one of the authentication mechanisms implemented by vault and is used on the GitLab end json web token is essentially a json document specifying uh who the GitLab instance is<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">who the user is who on behalf of which the execution happens and the job details requesting that specific access<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">it is signed by GitLab and it's verified by vault in process authorization in turn happens on the voltro entirely<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">so by sending the request GitLab requests a specific role from vault and the token in the context of this role is<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">either granted or not based on a match between the json web token describing the job and the limitations which are set in the role these are defined by so-called bound claims are now pretty important because they can limit the scope of that integration to a particular project or even particular branch within that project we're going to see that<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">in practice pretty soon part to understand is that those secrets need to be explicitly defined in GitLab ci yamo so runder will not extract every possible secret which is available to the role it will only extract the secrets which are<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">explicitly requested and declared in the GitLab ciam so when you look at the flow graphically once again it is GitLab which is generate generating jwt sending it to the runner forwards that jwt to volt which<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">then verifies that was GitLab to make sure that the signature is valid if it is a vault would return the token which was<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">previously requested by a runner based on the definition and if you look at the example jwt<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">you would see that it contains basically a personality of the job which user is requesting which pipeline id job id also which um project which specific project is doing this uh what is the job name um what is the branch in which this job is running in the context.<\/div>\n<h3 tabindex=\"0\" role=\"button\">Demo part:<\/h3>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">Let's see how this works in practice:<\/div>\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">I have set up a sample project which would be accessing credentials involved this project has two environments staging and production credentials are stored in environment-specific branches<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">protected by environment-specific policies and we will protect the production credentials from hijacking from any<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">other environments using bound claims.<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">So let's review first what do we have defined in volt there are two credentials production contains username and<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">password which is production-specific and staging secret contains the same type of credentials but the password is obviously different here we do have two policies which are symmetrical one is relating to the production environment the other is related to the staging environment as you might remember policies are essentially<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">granting a certain set of operations for a certain endpoint or branch so here we're talking about the secret sample project staging um and we are granting the capability to read and list and then<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\"><\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">we do have two roles.<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">those roles are production and staging specific and they would be different because they contain a specific bound claims so when you look at the staging role important parameter here is this bound claim it says that this role can be assumed only in the context of a specific project id so other GitLab project would not get access to that particular role, and the policy granted to it it is then essentially granting a sample project staging policy when you look at the production policy it contains even tighter control because it insists not only on having this particular project defined but also it can only be executed if the branch in the context of which the job is being run is a master so now let's<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">switch back to our system I have a very simple project which only contains a GitLab CI mo file and this GitLab yaml is containing two jobs which are meant to retrieve the secrets with the vault method and then expose them to the console by echoing them to the output now as you can see those jobs are running on every branch except master for the staging job and for the production job we only run this one on master the way those jobs are being assigned roles is defined by variables and when you expand this section you can see that there is a vault authentication<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">role variable which is defined separately for production and staging with the relevant values that are configuring the<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">job to actually retrieve request the right role policy and then eventually retrieve the right credentials and when you look at ci cd runs you can see that there is a feature branch pass which is actually showing the staging specific credentials here and for the production branch it would list the production-specific certificate uh production-specific password so now let's see let's assume a user is malicious and would like to hijack production certificate we know that in GitLab you cannot make changes in the master branch uh without proper merge request but uh let's assume our user wants to do that experimentation on a feature branch where he's allowed or she's allowed to do anything they want so going to feature branch I have two jobs and what I'm going to do is within that feature branch I will remove the limitation on the must on the production job to only run on the master branch I'm expecting now both of the jobs to be running on my on my next ci run again i can only commit them to feature branch without additional permission this is what I do and I can see that the pipeline has failed already let's see why this pipeline contains both jobs this is expected it contains a successful staging drop this is expected because we're in staging environment but the production job failed let's see why the reason it is failing is that vault is giving us 400 code it is validating claims and it see that the claim on the master branch is not satisfied so this role cannot be granted which is our way to fence production credentials and defend them against malicious use with this integration you can use vaults<\/div>\n<\/div>\n<\/div>\n<div class=\"cue-group style-scope ytd-transcript-body-renderer\" dir=\"ltr\">\n<div class=\"cues style-scope ytd-transcript-body-renderer\">\n<div class=\"cue style-scope ytd-transcript-body-renderer\" tabindex=\"0\" role=\"button\">to store your environment-specific credentials externally to GitLab manage them with a HashiCorp Vault and yet use them in the job as you need them on the go<\/div>\n<\/div>\n<\/div>\n<p dir=\"ltr\">\n","protected":false},"excerpt":{"rendered":"<p>\u05d4\u05e2\u05dc\u05e0\u05d5 \u05dc\u05db\u05d0\u05df \u05e1\u05e8\u05d8\u05d5\u05df \u05d7\u05d3\u05e9 \u05d5\u05e9\u05d9\u05de\u05d5\u05e9\u05d9, \u05d4\u05db\u05d5\u05dc\u05dc \u05d4\u05e1\u05d1\u05e8\u05d9\u05dd \u05d5\u05d4\u05d3\u05d2\u05de\u05d4 (\u05d3\u05de\u05d5). \u05d4\u05d3\u05de\u05d5 \u05de\u05e6\u05d9\u05d2 \u05d0\u05d9\u05da \u05d0\u05e4\u05e9\u05e8 \u05dc\u05d7\u05d1\u05e8 \u05d1\u05d9\u05df GitLab CI\u00a0 \u05dc\u05d1\u05d9\u05df HashiCorp Vault \u05e2&quot;\u05de \u05dc\u05d7\u05e9\u05d5\u05e3 \u05d0\u05ea \u05d4\u05e1\u05d5\u05d3\u05d5\u05ea (secrets) \u05dc- GitLab runners . \u05d4\u05d3\u05de\u05d5 \u05d2\u05dd \u05de\u05e6\u05d9\u05d2 \u05d0\u05d9\u05da \u05e1\u05d5\u05d3\u05d5\u05ea \u05d1\u05e1\u05d1\u05d9\u05d1\u05ea production \u05d9\u05db\u05d5\u05dc\u05d9\u05dd \u05dc\u05d4\u05d9\u05d5\u05ea \u05de\u05d5\u05d2\u05e0\u05d9\u05dd \u05de\u05e9\u05d9\u05de\u05d5\u05e9 \u05dc\u05d0 \u05e0\u05db\u05d5\u05df. \u05d1\u05ea\u05d7\u05d9\u05dc\u05ea \u05d4\u05e1\u05e8\u05d8\u05d5\u05df \u05d9\u05e9 \u05db\u05de\u05d4 \u05d3\u05e7\u05d5\u05ea \u05e9\u05dc \u05e8\u05e7\u05e2 \u05d5\u05de\u05d1\u05d5\u05d0 \u05e2\u05dc Vault \u05d5\u05e2\u05dc GitLab CI [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":5665,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,189,111,112,281,62],"tags":[256],"class_list":["post-5657","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-devsecops","category-gitlab","category-gitlab-ci","category-vault","category-62","tag-256"],"_links":{"self":[{"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/posts\/5657","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/comments?post=5657"}],"version-history":[{"count":0,"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/posts\/5657\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/media\/5665"}],"wp:attachment":[{"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/media?parent=5657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/categories?post=5657"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.almtoolbox.com\/blog_he\/wp-json\/wp\/v2\/tags?post=5657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}