[{"data":1,"prerenderedAt":817},["ShallowReactive",2],{"blog-\u002Fblog\u002Fsecuriser-pipeline-gitlab-ci-devsecops":3,"blog-related-\u002Fblog\u002Fsecuriser-pipeline-gitlab-ci-devsecops":798},{"id":4,"title":5,"body":6,"category":782,"date":783,"description":784,"draft":785,"extension":786,"meta":787,"navigation":192,"path":788,"readingTime":165,"seo":789,"sitemap":790,"stem":791,"tags":792,"__hash__":797},"blog\u002Fblog\u002Fsecuriser-pipeline-gitlab-ci-devsecops.md","Sécuriser une pipeline GitLab CI\u002FCD sans ralentir vos livraisons",{"type":7,"value":8,"toc":767},"minimark",[9,13,18,21,50,53,57,62,65,69,72,76,79,83,86,90,93,375,382,389,393,396,417,420,511,518,568,571,575,578,610,613,711,715,718,736,740,747,750,754,763],[10,11,12],"p",{},"Beaucoup d'équipes voient la sécurité comme un frein : un scan de vingt minutes, des centaines d'alertes que personne ne lit, des déploiements bloqués pour une vulnérabilité sans impact réel. Résultat, les contrôles sont contournés ou désactivés. Chez Cloud Corner, nous partons du principe inverse : une pipeline bien conçue rend la sécurité invisible tant que tout va bien, et bruyante uniquement quand un risque réel apparaît. Voici notre approche pour GitLab CI\u002FCD.",[14,15,17],"h2",{"id":16},"le-principe-décaler-à-gauche-mais-intelligemment","Le principe : décaler à gauche, mais intelligemment",[10,19,20],{},"Le « shift left » ne consiste pas à tout exécuter à chaque commit. Il s'agit de placer chaque contrôle au moment où il coûte le moins cher et apporte le plus d'information :",[22,23,24,32,38,44],"ul",{},[25,26,27,31],"li",{},[28,29,30],"strong",{},"Au commit"," : détection de secrets et SAST, rapides et incrémentaux.",[25,33,34,37],{},[28,35,36],{},"À la merge request"," : scan des dépendances, analyse des fichiers Dockerfile et d'infrastructure.",[25,39,40,43],{},[28,41,42],{},"Au build"," : scan de l'image, génération du SBOM, signature.",[25,45,46,49],{},[28,47,48],{},"Au déploiement"," : vérification de la signature et des politiques d'admission.",[10,51,52],{},"Les jobs de sécurité tournent en parallèle des tests, jamais en série derrière eux. C'est le premier levier pour ne pas allonger le temps de pipeline.",[14,54,56],{"id":55},"les-briques-à-intégrer","Les briques à intégrer",[58,59,61],"h3",{"id":60},"sast-avec-semgrep","SAST avec Semgrep",[10,63,64],{},"Semgrep analyse le code source avec des règles lisibles et facilement extensibles. Nous le lançons uniquement sur les fichiers modifiés en merge request, et sur l'ensemble du dépôt lors d'un passage planifié nocturne.",[58,66,68],{"id":67},"scan-des-dépendances-et-des-images","Scan des dépendances et des images",[10,70,71],{},"Les dépendances applicatives (lockfiles npm, pip, Maven) et les images de conteneurs sont la source la plus fréquente de vulnérabilités connues. Trivy couvre les deux avec un seul outil, en mode « filesystem » pour le code et en mode « image » pour le résultat du build.",[58,73,75],{"id":74},"détection-de-secrets","Détection de secrets",[10,77,78],{},"Gitleaks ou la détection native de GitLab repèrent les clés d'API et mots de passe committés. Activez-la aussi en pré-commit côté développeur : un secret qui n'entre jamais dans l'historique Git n'a pas besoin d'être révoqué.",[58,80,82],{"id":81},"sbom-et-signature","SBOM et signature",[10,84,85],{},"Un SBOM (au format CycloneDX ou SPDX) liste précisément ce que contient votre artefact. Associé à une signature cosign, il permet de prouver l'origine d'une image et de réagir en quelques minutes lorsqu'une nouvelle faille est publiée.",[14,87,89],{"id":88},"un-exemple-de-pipeline-avec-to-be-continuous","Un exemple de pipeline avec to-be-continuous",[10,91,92],{},"Le framework to-be-continuous fournit des composants GitLab prêts à l'emploi qui évitent de maintenir des dizaines de lignes de YAML. Voici un extrait réaliste :",[94,95,100],"pre",{"className":96,"code":97,"language":98,"meta":99,"style":99},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark","include:\n  - component: $CI_SERVER_FQDN\u002Fto-be-continuous\u002Fdocker\u002Fgitlab-ci-docker@6\n    inputs:\n      trivy-enabled: true\n      sbom-disabled: false\n  - component: $CI_SERVER_FQDN\u002Fto-be-continuous\u002Fsemgrep\u002Fgitlab-ci-semgrep@3\n  - component: $CI_SERVER_FQDN\u002Fto-be-continuous\u002Fgitleaks\u002Fgitlab-ci-gitleaks@3\n\nstages:\n  - build\n  - test\n  - package-build\n  - package-test\n  - publish\n  - deploy\n\nsign-image:\n  stage: publish\n  image:\n    name: gcr.io\u002Fprojectsigstore\u002Fcosign:v2.4.1\n    entrypoint: [\"\"]\n  id_tokens:\n    SIGSTORE_ID_TOKEN:\n      aud: sigstore\n  script:\n    - cosign sign --yes \"$CI_REGISTRY_IMAGE@$(cat digest.txt)\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n","yaml","",[101,102,103,116,132,140,152,163,175,187,194,202,210,218,226,234,242,250,255,263,273,281,292,310,318,326,337,345,354,362],"code",{"__ignoreMap":99},[104,105,108,112],"span",{"class":106,"line":107},"line",1,[104,109,111],{"class":110},"sQzsp","include",[104,113,115],{"class":114},"sP7_E",":\n",[104,117,119,122,125,128],{"class":106,"line":118},2,[104,120,121],{"class":114},"  -",[104,123,124],{"class":110}," component",[104,126,127],{"class":114},":",[104,129,131],{"class":130},"s_sjI"," $CI_SERVER_FQDN\u002Fto-be-continuous\u002Fdocker\u002Fgitlab-ci-docker@6\n",[104,133,135,138],{"class":106,"line":134},3,[104,136,137],{"class":110},"    inputs",[104,139,115],{"class":114},[104,141,143,146,148],{"class":106,"line":142},4,[104,144,145],{"class":110},"      trivy-enabled",[104,147,127],{"class":114},[104,149,151],{"class":150},"syTEX"," true\n",[104,153,155,158,160],{"class":106,"line":154},5,[104,156,157],{"class":110},"      sbom-disabled",[104,159,127],{"class":114},[104,161,162],{"class":150}," false\n",[104,164,166,168,170,172],{"class":106,"line":165},6,[104,167,121],{"class":114},[104,169,124],{"class":110},[104,171,127],{"class":114},[104,173,174],{"class":130}," $CI_SERVER_FQDN\u002Fto-be-continuous\u002Fsemgrep\u002Fgitlab-ci-semgrep@3\n",[104,176,178,180,182,184],{"class":106,"line":177},7,[104,179,121],{"class":114},[104,181,124],{"class":110},[104,183,127],{"class":114},[104,185,186],{"class":130}," $CI_SERVER_FQDN\u002Fto-be-continuous\u002Fgitleaks\u002Fgitlab-ci-gitleaks@3\n",[104,188,190],{"class":106,"line":189},8,[104,191,193],{"emptyLinePlaceholder":192},true,"\n",[104,195,197,200],{"class":106,"line":196},9,[104,198,199],{"class":110},"stages",[104,201,115],{"class":114},[104,203,205,207],{"class":106,"line":204},10,[104,206,121],{"class":114},[104,208,209],{"class":130}," build\n",[104,211,213,215],{"class":106,"line":212},11,[104,214,121],{"class":114},[104,216,217],{"class":130}," test\n",[104,219,221,223],{"class":106,"line":220},12,[104,222,121],{"class":114},[104,224,225],{"class":130}," package-build\n",[104,227,229,231],{"class":106,"line":228},13,[104,230,121],{"class":114},[104,232,233],{"class":130}," package-test\n",[104,235,237,239],{"class":106,"line":236},14,[104,238,121],{"class":114},[104,240,241],{"class":130}," publish\n",[104,243,245,247],{"class":106,"line":244},15,[104,246,121],{"class":114},[104,248,249],{"class":130}," deploy\n",[104,251,253],{"class":106,"line":252},16,[104,254,193],{"emptyLinePlaceholder":192},[104,256,258,261],{"class":106,"line":257},17,[104,259,260],{"class":110},"sign-image",[104,262,115],{"class":114},[104,264,266,269,271],{"class":106,"line":265},18,[104,267,268],{"class":110},"  stage",[104,270,127],{"class":114},[104,272,241],{"class":130},[104,274,276,279],{"class":106,"line":275},19,[104,277,278],{"class":110},"  image",[104,280,115],{"class":114},[104,282,284,287,289],{"class":106,"line":283},20,[104,285,286],{"class":110},"    name",[104,288,127],{"class":114},[104,290,291],{"class":130}," gcr.io\u002Fprojectsigstore\u002Fcosign:v2.4.1\n",[104,293,295,298,300,303,307],{"class":106,"line":294},21,[104,296,297],{"class":110},"    entrypoint",[104,299,127],{"class":114},[104,301,302],{"class":114}," [",[104,304,306],{"class":305},"sjJ54","\"\"",[104,308,309],{"class":114},"]\n",[104,311,313,316],{"class":106,"line":312},22,[104,314,315],{"class":110},"  id_tokens",[104,317,115],{"class":114},[104,319,321,324],{"class":106,"line":320},23,[104,322,323],{"class":110},"    SIGSTORE_ID_TOKEN",[104,325,115],{"class":114},[104,327,329,332,334],{"class":106,"line":328},24,[104,330,331],{"class":110},"      aud",[104,333,127],{"class":114},[104,335,336],{"class":130}," sigstore\n",[104,338,340,343],{"class":106,"line":339},25,[104,341,342],{"class":110},"  script",[104,344,115],{"class":114},[104,346,348,351],{"class":106,"line":347},26,[104,349,350],{"class":114},"    -",[104,352,353],{"class":130}," cosign sign --yes \"$CI_REGISTRY_IMAGE@$(cat digest.txt)\"\n",[104,355,357,360],{"class":106,"line":356},27,[104,358,359],{"class":110},"  rules",[104,361,115],{"class":114},[104,363,365,367,370,372],{"class":106,"line":364},28,[104,366,350],{"class":114},[104,368,369],{"class":110}," if",[104,371,127],{"class":114},[104,373,374],{"class":130}," $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n",[10,376,377,378,381],{},"Le job de signature utilise un jeton OIDC émis par GitLab (",[101,379,380],{},"id_tokens",") : aucune clé privée n'est stockée dans le projet. C'est la signature « keyless » de Sigstore, vérifiable ensuite par l'identité de la pipeline.",[10,383,384,385,388],{},"Pensez à épingler les versions des composants et des images d'outils, idéalement par digest. Une pipeline de sécurité qui tire un ",[101,386,387],{},"latest"," est elle-même un risque de chaîne d'approvisionnement.",[14,390,392],{"id":391},"une-politique-qui-ne-bloque-que-lexploitable","Une politique qui ne bloque que l'exploitable",[10,394,395],{},"Bloquer sur chaque CVE est le meilleur moyen de se faire contourner. Notre règle de base :",[397,398,399,405,411],"ol",{},[25,400,401,404],{},[28,402,403],{},"Bloquer"," les vulnérabilités de sévérité haute ou critique, avec un correctif disponible, dans un composant réellement présent à l'exécution.",[25,406,407,410],{},[28,408,409],{},"Alerter sans bloquer"," pour le reste, avec un ticket créé automatiquement et une échéance.",[25,412,413,416],{},[28,414,415],{},"Ignorer explicitement"," les faux positifs et les risques acceptés, dans un fichier versionné, avec un motif et une date d'expiration.",[10,418,419],{},"Pour Trivy, cela donne par exemple :",[94,421,423],{"className":96,"code":422,"language":98,"meta":99,"style":99},"trivy-image:\n  stage: package-test\n  image:\n    name: aquasec\u002Ftrivy:0.58.0\n    entrypoint: [\"\"]\n  script:\n    - trivy image\n        --severity HIGH,CRITICAL\n        --ignore-unfixed\n        --ignorefile .trivyignore.yaml\n        --exit-code 1\n        \"$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\"\n",[101,424,425,432,440,446,455,467,473,480,485,490,495,500],{"__ignoreMap":99},[104,426,427,430],{"class":106,"line":107},[104,428,429],{"class":110},"trivy-image",[104,431,115],{"class":114},[104,433,434,436,438],{"class":106,"line":118},[104,435,268],{"class":110},[104,437,127],{"class":114},[104,439,233],{"class":130},[104,441,442,444],{"class":106,"line":134},[104,443,278],{"class":110},[104,445,115],{"class":114},[104,447,448,450,452],{"class":106,"line":142},[104,449,286],{"class":110},[104,451,127],{"class":114},[104,453,454],{"class":130}," aquasec\u002Ftrivy:0.58.0\n",[104,456,457,459,461,463,465],{"class":106,"line":154},[104,458,297],{"class":110},[104,460,127],{"class":114},[104,462,302],{"class":114},[104,464,306],{"class":305},[104,466,309],{"class":114},[104,468,469,471],{"class":106,"line":165},[104,470,342],{"class":110},[104,472,115],{"class":114},[104,474,475,477],{"class":106,"line":177},[104,476,350],{"class":114},[104,478,479],{"class":130}," trivy image\n",[104,481,482],{"class":106,"line":189},[104,483,484],{"class":130},"        --severity HIGH,CRITICAL\n",[104,486,487],{"class":106,"line":196},[104,488,489],{"class":130},"        --ignore-unfixed\n",[104,491,492],{"class":106,"line":204},[104,493,494],{"class":130},"        --ignorefile .trivyignore.yaml\n",[104,496,497],{"class":106,"line":212},[104,498,499],{"class":130},"        --exit-code 1\n",[104,501,502,505,508],{"class":106,"line":220},[104,503,504],{"class":305},"        \"",[104,506,507],{"class":130},"$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA",[104,509,510],{"class":305},"\"\n",[10,512,513,514,517],{},"L'option ",[101,515,516],{},"--ignore-unfixed"," écarte les failles sans correctif disponible : bloquer sur ce qu'on ne peut pas corriger n'aide personne. Le fichier d'exceptions peut ressembler à ceci :",[94,519,521],{"className":96,"code":520,"language":98,"meta":99,"style":99},"vulnerabilities:\n  - id: CVE-2025-00000\n    statement: \"Fonction vulnérable non appelée par notre code\"\n    expired_at: 2026-12-31\n",[101,522,523,530,542,557],{"__ignoreMap":99},[104,524,525,528],{"class":106,"line":107},[104,526,527],{"class":110},"vulnerabilities",[104,529,115],{"class":114},[104,531,532,534,537,539],{"class":106,"line":118},[104,533,121],{"class":114},[104,535,536],{"class":110}," id",[104,538,127],{"class":114},[104,540,541],{"class":130}," CVE-2025-00000\n",[104,543,544,547,549,552,555],{"class":106,"line":134},[104,545,546],{"class":110},"    statement",[104,548,127],{"class":114},[104,550,551],{"class":305}," \"",[104,553,554],{"class":130},"Fonction vulnérable non appelée par notre code",[104,556,510],{"class":305},[104,558,559,562,564],{"class":106,"line":142},[104,560,561],{"class":110},"    expired_at",[104,563,127],{"class":114},[104,565,567],{"class":566},"s_hVV"," 2026-12-31\n",[10,569,570],{},"L'expiration est essentielle : une exception sans date devient vite une dette oubliée. Pour affiner la priorisation, croisez la sévérité avec la présence de la faille dans le catalogue KEV de la CISA ou son score EPSS, qui estiment l'exploitation réelle.",[14,572,574],{"id":573},"gérer-les-secrets-proprement","Gérer les secrets proprement",[10,576,577],{},"Le meilleur secret est celui qui n'existe pas. Par ordre de préférence :",[22,579,580,586,596],{},[25,581,582,585],{},[28,583,584],{},"OIDC fédéré"," : la pipeline s'authentifie auprès du cloud (AWS, GCP, Azure) ou de Vault avec un jeton court, lié au projet et à la branche. Aucun identifiant statique.",[25,587,588,591,592,595],{},[28,589,590],{},"HashiCorp Vault"," : les secrets sont lus à la volée via ",[101,593,594],{},"secrets:"," dans le job, avec des politiques en moindre privilège.",[25,597,598,601,602,605,606,609],{},[28,599,600],{},"Variables CI\u002FCD"," : en dernier recours, toujours ",[28,603,604],{},"masquées"," (absentes des logs), ",[28,607,608],{},"protégées"," (disponibles uniquement sur les branches et tags protégés) et limitées à l'environnement concerné.",[10,611,612],{},"Exemple de lecture depuis Vault avec un jeton OIDC :",[94,614,616],{"className":96,"code":615,"language":98,"meta":99,"style":99},"deploy:\n  stage: deploy\n  id_tokens:\n    VAULT_ID_TOKEN:\n      aud: https:\u002F\u002Fvault.example.org\n  secrets:\n    DB_PASSWORD:\n      vault: production\u002Fdb\u002Fpassword@secret\n      file: false\n  script:\n    - .\u002Fdeploy.sh\n  environment: production\n",[101,617,618,625,633,639,646,655,662,669,679,688,694,701],{"__ignoreMap":99},[104,619,620,623],{"class":106,"line":107},[104,621,622],{"class":110},"deploy",[104,624,115],{"class":114},[104,626,627,629,631],{"class":106,"line":118},[104,628,268],{"class":110},[104,630,127],{"class":114},[104,632,249],{"class":130},[104,634,635,637],{"class":106,"line":134},[104,636,315],{"class":110},[104,638,115],{"class":114},[104,640,641,644],{"class":106,"line":142},[104,642,643],{"class":110},"    VAULT_ID_TOKEN",[104,645,115],{"class":114},[104,647,648,650,652],{"class":106,"line":154},[104,649,331],{"class":110},[104,651,127],{"class":114},[104,653,654],{"class":130}," https:\u002F\u002Fvault.example.org\n",[104,656,657,660],{"class":106,"line":165},[104,658,659],{"class":110},"  secrets",[104,661,115],{"class":114},[104,663,664,667],{"class":106,"line":177},[104,665,666],{"class":110},"    DB_PASSWORD",[104,668,115],{"class":114},[104,670,671,674,676],{"class":106,"line":189},[104,672,673],{"class":110},"      vault",[104,675,127],{"class":114},[104,677,678],{"class":130}," production\u002Fdb\u002Fpassword@secret\n",[104,680,681,684,686],{"class":106,"line":196},[104,682,683],{"class":110},"      file",[104,685,127],{"class":114},[104,687,162],{"class":150},[104,689,690,692],{"class":106,"line":204},[104,691,342],{"class":110},[104,693,115],{"class":114},[104,695,696,698],{"class":106,"line":212},[104,697,350],{"class":114},[104,699,700],{"class":130}," .\u002Fdeploy.sh\n",[104,702,703,706,708],{"class":106,"line":220},[104,704,705],{"class":110},"  environment",[104,707,127],{"class":114},[104,709,710],{"class":130}," production\n",[14,712,714],{"id":713},"mesurer-pour-ne-pas-ralentir","Mesurer pour ne pas ralentir",[10,716,717],{},"Une pipeline sécurisée reste une pipeline rapide si l'on garde quelques réflexes :",[22,719,720,727,730,733],{},[25,721,722,723,726],{},"exécuter les scans en parallèle des tests avec ",[101,724,725],{},"needs",", pas après ;",[25,728,729],{},"mettre en cache les bases de vulnérabilités de Trivy entre les jobs ;",[25,731,732],{},"limiter les scans complets aux branches principales et aux exécutions planifiées ;",[25,734,735],{},"suivre le temps moyen de pipeline et le délai de correction des vulnérabilités, deux indicateurs qui disent si la sécurité aide ou gêne vos équipes.",[14,737,739],{"id":738},"déployer-progressivement","Déployer progressivement",[10,741,742,743,746],{},"Inutile de tout activer le même jour. Nous recommandons de commencer en mode « observation » : les jobs tournent, remontent leurs résultats dans la merge request, mais ne bloquent rien (",[101,744,745],{},"allow_failure: true","). Après deux ou trois semaines, vous connaissez le bruit de fond, vous avez traité les faux positifs évidents et vous pouvez passer les contrôles les plus fiables en mode bloquant. Cette montée en charge évite le rejet par les équipes, qui voient la sécurité comme une aide plutôt que comme une sanction.",[10,748,749],{},"Désignez aussi un responsable par projet pour le traitement des alertes. Une alerte sans propriétaire finit toujours par être ignorée, quel que soit l'outil.",[14,751,753],{"id":752},"besoin-dun-coup-de-main","Besoin d'un coup de main ?",[10,755,756,757,762],{},"Intégrer ces contrôles dans vos pipelines existantes, définir une politique réaliste ou migrer vos secrets vers OIDC et Vault demande un peu de méthode. Si vous souhaitez un regard extérieur ou un accompagnement, n'hésitez pas à ",[758,759,761],"a",{"href":760},"\u002F#contact","nous contacter",".",[764,765,766],"style",{},"html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":99,"searchDepth":118,"depth":118,"links":768},[769,770,776,777,778,779,780,781],{"id":16,"depth":118,"text":17},{"id":55,"depth":118,"text":56,"children":771},[772,773,774,775],{"id":60,"depth":134,"text":61},{"id":67,"depth":134,"text":68},{"id":74,"depth":134,"text":75},{"id":81,"depth":134,"text":82},{"id":88,"depth":118,"text":89},{"id":391,"depth":118,"text":392},{"id":573,"depth":118,"text":574},{"id":713,"depth":118,"text":714},{"id":738,"depth":118,"text":739},{"id":752,"depth":118,"text":753},"DevSecOps","2026-09-22","SAST, scan de dépendances et d'images, secrets, SBOM, signature cosign : comment intégrer la sécurité dans GitLab CI\u002FCD sans freiner vos mises en production.",false,"md",{},"\u002Fblog\u002Fsecuriser-pipeline-gitlab-ci-devsecops",{"title":5,"description":784},{"loc":788,"lastmod":783},"blog\u002Fsecuriser-pipeline-gitlab-ci-devsecops",[793,794,795,796],"gitlab","ci-cd","devsecops","securite","tEIor70QDO7KjqNX-22w3dOryjhJZpmjLEuS5fe1_nY",[799,805,811],{"path":800,"title":801,"description":802,"date":803,"category":804,"readingTime":177},"\u002Fblog\u002Fapplication-mobile-pwa-native-tauri","Application mobile : native, Flutter, PWA ou Tauri 2, comment choisir ?","Native, cross-platform, PWA ou Tauri 2 : comparatif concret selon l'accès matériel, le hors-ligne, la maintenance et la publication sur les stores.","2026-10-06","Mobile",{"path":806,"title":807,"description":808,"date":809,"category":810,"readingTime":165},"\u002Fblog\u002Fseo-technique-nuxt","SEO technique avec Nuxt : le guide pour un site rapide et bien référencé","Rendu SSR ou pré-rendu, useSeoMeta, canoniques, sitemap, JSON-LD, Core Web Vitals : les réglages SEO techniques à maîtriser sur un site Nuxt 4.","2026-09-10","SEO",{"path":812,"title":813,"description":814,"date":815,"category":816,"readingTime":165},"\u002Fblog\u002Fgitops-flux-kubernetes","GitOps avec Flux CD : piloter Kubernetes depuis Git, sans kubectl en production","GitOps avec Flux CD sur Kubernetes : structure de dépôt, Kustomization, HelmRelease, secrets SOPS, promotion entre environnements et validation en CI.","2026-08-28","Infrastructure",1792329028555]